Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Dois-je utiliser une colonne varchar(max) en ligne ou la stocker dans une table séparée ?

Gardez-le en ligne. Sous les couvertures, SQL Server stocke déjà les colonnes MAX dans une "unité d'allocation" distincte depuis SQL 2005. Voir Organisation des tables et des index. Cela revient en fait exactement au même que de conserver la colonne MAX dans sa propre table, mais sans aucun inconvénient à le faire explicitement.

Avoir une table explicite serait en fait à la fois plus lent (à cause de la contrainte de clé étrangère) et consomme plus d'espace (à cause de la duplication DetaiID). Sans oublier que cela nécessite plus de code et que les bogues sont introduits en... écrivant du code.

texte alternatif http://i.msdn.microsoft.com/ms189051.3be61595-d405-4b30-9794-755842d7db7e(en-us,SQL.100).gif

Mettre à jour

Pour vérifier l'emplacement réel des données, un simple test peut le montrer :

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

Le %%physloc%% la pseudo colonne affichera l'emplacement physique réel de la ligne, dans mon cas c'était la page 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)   

Toutes les valeurs de colonne sauf TEXT et NTEXT ont été stockées en ligne, y compris les types MAX.
Après avoir modifié les options de table et inséré une nouvelle ligne (sp_tableoption n'affecte pas les lignes existantes), les types MAX ont été expulsés dans leur propre stockage :

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);

Notez comment les colonnes m_a et nm_a sont maintenant un pointeur de texte dans l'unité d'allocation 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)                    

Par souci d'achèvement, nous pouvons également forcer l'un des champs non max hors ligne :

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

Notez comment la colonne v_a est stockée dans le stockage 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) 

Ainsi, comme d'autres l'ont déjà commenté, les types MAX sont stockés en ligne par défaut, s'ils conviennent. Pour de nombreux projets DW, cela serait inacceptable car les charges DW typiques doivent analyser ou au moins analyser la plage, donc le sp_tableoption ..., 'large value types out of row', '1' Devrait être utilisé. Notez que cela n'affecte pas les lignes existantes, dans mon test pas même lors de la reconstruction de l'index , l'option doit donc être activée tôt.

Pour la plupart des charges de type OLTP, le fait que les types MAX soient stockés en ligne si possible est en fait un avantage, car le modèle d'accès OLTP est à rechercher et la largeur de ligne a peu d'impact sur lui.

Néanmoins, en ce qui concerne la question initiale :un tableau séparé n'est pas nécessaire. Activer les large value types out of row l'option obtient le même résultat à un coût gratuit pour le développement/test.