Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Devo usar uma coluna varchar(max) inline ou armazená-la em uma tabela separada?


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.