sql >> データベース >  >> RDS >> Sqlserver

インラインvarchar(max)列を使用する必要がありますか、それとも別のテーブルに保存する必要がありますか?

    インラインにしてください。裏でSQLServerは、SQL 2005以降、MAX列を別の「アロケーションユニット」にすでに格納しています。テーブルとインデックスの編成を参照してください。これは事実上、MAX列を独自のテーブルに保持することとまったく同じですが、明示的にそうすることの欠点はありません。

    明示的なテーブルがあると、実際には両方とも遅くなります (外部キー制約のため)そしてより多くのスペースを消費する (DetaiIDの重複のため)。言うまでもなく、より多くのコードが必要であり、バグは...コードを書くことによって導入されます。

    代替テキストhttp://i.msdn.microsoft.com/ms189051.3be61595-d405-4b30-9794-755842d7db7e(en-us,SQL.100).gif

    更新

    データの実際の場所を確認するために、簡単なテストでデータを表示できます:

    use tempdb;
    go
    
    create table a (
      id int identity(1,1) not null primary key,
      v_a varchar(8000),
      nv_a nvarchar(4000),
      m_a varchar(max),
      nm_a nvarchar(max),
      t text,
      nt ntext);
    go
    
    insert into a (v_a, nv_a, m_a, nm_a, t, nt)
    values ('v_a', N'nv_a', 'm_a', N'nm_a', 't', N'nt');
    go
    
    select %%physloc%%,* from a
    go
    

    %%physloc%% 疑似列には、行の実際の物理的な場所が表示されます。私の場合は200ページでした:

    dbcc traceon(3604)
    dbcc page(2,1, 200, 3)
    
    Slot 0 Column 2 Offset 0x19 Length 3 Length (physical) 3
    v_a = v_a                            
    Slot 0 Column 3 Offset 0x1c Length 8 Length (physical) 8
    nv_a = nv_a                          
    m_a = [BLOB Inline Data] Slot 0 Column 4 Offset 0x24 Length 3 Length (physical) 3
    m_a = 0x6d5f61                       
    nm_a = [BLOB Inline Data] Slot 0 Column 5 Offset 0x27 Length 8 Length (physical) 8
    nm_a = 0x6e006d005f006100            
    t = [Textpointer] Slot 0 Column 6 Offset 0x2f Length 16 Length (physical) 16
    TextTimeStamp = 131137536            RowId = (1:182:0)                    
    nt = [Textpointer] Slot 0 Column 7 Offset 0x3f Length 16 Length (physical) 16
    TextTimeStamp = 131203072            RowId = (1:182:1)   
    

    TEXTとNTEXTを除くすべての列の値は、MAXタイプを含めてインラインで格納されました。
    テーブルオプションを変更して新しい行を挿入した後(sp_tableoptionは既存の行に影響しません)、MAXタイプは独自のストレージに削除されました。

    sp_tableoption 'a' , 'large value types out of row', '1';
    insert into a (v_a, nv_a, m_a, nm_a, t, nt)
    values ('2v_a', N'2nv_a', '2m_a', N'2nm_a', '2t', N'2nt');    
    dbcc page(2,1, 200, 3);
    

    m_a列とnm_a列がLOBアロケーションユニットへのテキストポインタになっていることに注意してください。

    Slot 1 Column 2 Offset 0x19 Length 4 Length (physical) 4
    v_a = 2v_a                           
    Slot 1 Column 3 Offset 0x1d Length 10 Length (physical) 10
    nv_a = 2nv_a                         
    m_a = [Textpointer] Slot 1 Column 4 Offset 0x27 Length 16 Length (physical) 16
    TextTimeStamp = 131268608            RowId = (1:182:2)                    
    nm_a = [Textpointer] Slot 1 Column 5 Offset 0x37 Length 16 Length (physical) 16
    TextTimeStamp = 131334144            RowId = (1:182:3)                    
    t = [Textpointer] Slot 1 Column 6 Offset 0x47 Length 16 Length (physical) 16
    TextTimeStamp = 131399680            RowId = (1:182:4)                    
    nt = [Textpointer] Slot 1 Column 7 Offset 0x57 Length 16 Length (physical) 16
    TextTimeStamp = 131465216            RowId = (1:182:5)                    
    

    完了のために、max以外のフィールドの1つを強制的に行から外すこともできます:

    update a set v_a = replicate('X', 8000);
    dbcc page(2,1, 200, 3);
    

    v_a列が行オーバーフローストレージにどのように格納されているかに注意してください:

    Slot 0 Column 1 Offset 0x4 Length 4 Length (physical) 4
    v_a = [BLOB Inline Root] Slot 0 Column 2 Offset 0x19 Length 24 Length (physical) 24
    Level = 0                            Unused = 99                          UpdateSeq = 1
    TimeStamp = 1098383360               
    Link 0
    Size = 8000                          RowId = (1:176:0) 
    

    したがって、他の人がすでにコメントしているように、MAXタイプは、適切な場合、デフォルトでインラインで保存されます。多くのDWプロジェクトでは、通常のDW負荷をスキャンするか、少なくとも範囲スキャンする必要があるため、これは受け入れられません。したがって、sp_tableoption ..., 'large value types out of row', '1' 使用すべきです。私のテストでは、インデックスの再構築でも、これは既存の行には影響しないことに注意してください。 、したがって、オプションは早期にオンにする必要があります。

    ほとんどのOLTPタイプのロードでは、可能であればMAXタイプがインラインで格納されるという事実は実際には利点です。これは、OLTPアクセスパターンがシークであり、行幅がそれにほとんど影響を与えないためです。

    それでも、元の質問に関しては、別のテーブルは必要ありません。 large value types out of rowをオンにする オプションは、開発/テストの無料コストで同じ結果を達成します。



    1. OracleのRANK、DENSE_RANK、およびROW_NUMBER関数

    2. PostgreSQLで英数字のみを含む行を返す2つの方法

    3. PostgreSQL11の新しいパーティショニング機能を利用する方法

    4. sequelizeを使用してローカルノードアプリからherokupostgresqlデータベースに接続できません