Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Soll ich eine Inline-Varchar(max)-Spalte verwenden oder in einer separaten Tabelle speichern?

Halten Sie es inline. Unter der Decke speichert SQL Server bereits seit SQL 2005 die MAX-Spalten in einer separaten 'Zuweisungseinheit'. Siehe Tabellen- und Indexorganisation. Dies ist im Endeffekt genau das Gleiche wie das Behalten der MAX-Spalte in ihrer eigenen Tabelle, aber ohne jeglichen Nachteil, dies explizit zu tun.

Eine explizite Tabelle zu haben, wäre eigentlich beides langsamer (aufgrund der Fremdschlüsseleinschränkung) und verbrauchen mehr Platz (wegen der DetaiID-Duplizierung). Ganz zu schweigen davon, dass mehr Code erforderlich ist und Fehler eingeführt werden, indem ... Code geschrieben wird.

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

Aktualisieren

Um den tatsächlichen Speicherort von Daten zu überprüfen, kann ein einfacher Test dies zeigen:

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

Der %%physloc%% Pseudo-Spalte zeigt die tatsächliche physische Position der Zeile an, in meinem Fall war es Seite 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)   

Alle Spaltenwerte außer TEXT und NTEXT wurden inline gespeichert, einschließlich der MAX-Typen.
Nach dem Ändern der Tabellenoptionen und dem Einfügen einer neuen Zeile (sp_tableoption wirkt sich nicht auf vorhandene Zeilen aus) wurden die MAX-Typen in ihren eigenen Speicher verdrängt:

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

Beachten Sie, dass die Spalten m_a und nm_a jetzt ein Textzeiger in die LOB-Zuweisungseinheit sind:

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)                    

Der Vollständigkeit halber können wir auch eines der Nicht-Max-Felder aus der Reihe zwingen:

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

Beachten Sie, wie die v_a-Spalte im Row-Overflow-Speicher gespeichert wird:

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) 

Wie andere bereits kommentiert haben, werden die MAX-Typen standardmäßig inline gespeichert, wenn sie passen. Für viele DW-Projekte wäre dies nicht akzeptabel, da die typischen DW-Ladevorgänge scannen oder zumindest einen Bereichsscan durchführen müssen, also die sp_tableoption ..., 'large value types out of row', '1' sollte benutzt werden. Beachten Sie, dass dies keine Auswirkungen auf vorhandene Zeilen hat, in meinem Test nicht einmal beim Indexneuaufbau , daher muss die Option frühzeitig aktiviert werden.

Für die meisten OLTP-Type-Loads ist es aber eigentlich von Vorteil, dass MAX-Types möglichst inline gespeichert werden, da das OLTP-Zugriffsmuster zu suchen ist und die Zeilenbreite darauf kaum Einfluss hat.

Trotzdem zur ursprünglichen Frage:Eine separate Tabelle ist nicht erforderlich. Aktivieren der large value types out of row Option erzielt das gleiche Ergebnis bei kostenlosen Entwicklungs-/Testkosten.