Mantenha-o em linha. Nos bastidores, o SQL Server já armazena as colunas MAX em uma 'unidade de alocação' separada desde o SQL 2005. Consulte Organização de tabelas e índices. Na verdade, isso é exatamente o mesmo que manter a coluna MAX em sua própria tabela, mas sem nenhuma desvantagem de fazê-lo explicitamente.
Ter uma tabela explícita seria mais lento (por causa da restrição de chave estrangeira) e consumir mais espaço (por causa da duplicação do DetaiID). Sem mencionar que requer mais código, e os bugs são introduzidos por... escrevendo código.
texto alternativo http://i.msdn.microsoft.com/ms189051.3be61595-d405-4b30-9794-755842d7db7e(pt-br,SQL.100).gif
Atualizar
Para verificar a localização real dos dados, um teste simples pode mostrá-lo:
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
O
%%physloc%%
pseudo coluna mostrará a localização física real da linha, no meu caso foi a página 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)
Todos os valores de coluna, exceto TEXT e NTEXT, foram armazenados inline, incluindo os tipos MAX.
Depois de alterar as opções da tabela e inserir uma nova linha (sp_tableoption não afeta as linhas existentes), os tipos MAX foram despejados em seu próprio armazenamento:
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);
Observe como as colunas m_a e nm_a agora são um Textpointer na unidade de alocação 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)
Para fins de conclusão, também podemos forçar um dos campos não máximos para fora da linha:
update a set v_a = replicate('X', 8000);
dbcc page(2,1, 200, 3);
Observe como a coluna v_a é armazenada no armazenamento 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)
Então, como outros já comentaram, os tipos MAX são armazenados inline por padrão, se eles se encaixam. Para muitos projetos de DW, isso seria inaceitável porque as cargas típicas de DW devem varrer ou pelo menos varredura de intervalo, portanto, a
sp_tableoption ..., 'large value types out of row', '1'
deve ser usado. Observe que isso não afeta as linhas existentes, no meu teste nem mesmo na reconstrução do índice , portanto, a opção deve ser ativada antecipadamente. Para a maioria das cargas do tipo OLTP, o fato de que os tipos MAX são armazenados em linha, se possível, é realmente uma vantagem, já que o padrão de acesso OLTP é buscar e a largura da linha tem pouco impacto sobre ele.
No entanto, em relação à pergunta original:não é necessária tabela separada. Ativando os
large value types out of row
opção atinge o mesmo resultado a um custo gratuito para desenvolvimento/teste.