インラインにしてください。内部的には、SQL Server は SQL 2005 以降、MAX 列を別の「アロケーション ユニット」に格納しています。テーブルとインデックスの編成を参照してください。これは事実上、MAX 列を独自のテーブルに保持することとまったく同じですが、明示的に保持することの欠点はありません。
明示的なテーブルを使用すると、実際には速度が低下し (外部キー制約のため)、より多くのスペースを消費します(DetaiID の重複のため)。言うまでもなく、より多くのコードが必要であり、バグはコードを書くことによって導入されます。
代替テキスト http://i.msdn.microsoft.com/ms189051.3be61595-d405-4b30-9794-755842d7db7e(ja-jp,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 アロケーション ユニットへの Textpointer になっていることに注意してください。
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 列が Row-Overflow ストレージに格納される方法に注意してください。
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
すると、開発/テストの費用は無料で同じ結果が得られます。