sql >> Database >  >> RDS >> Sqlserver

Moet ik een inline varchar(max)-kolom gebruiken of deze in een aparte tabel opslaan?

Houd het in lijn. Onder de dekens slaat SQL Server de MAX-kolommen al sinds SQL 2005 op in een aparte 'allocation unit'. Zie Tabel en Index Organisatie. Dit is in feite hetzelfde als het houden van de MAX-kolom in zijn eigen tabel, maar zonder enig nadeel om dit expliciet te doen.

Het hebben van een expliciete tabel zou eigenlijk beide langzamer . zijn (vanwege de externe sleutelbeperking) en meer ruimte in beslag nemen (vanwege de DetailID-duplicatie). Om nog maar te zwijgen van het feit dat er meer code voor nodig is en dat er bugs worden geïntroduceerd door... code te schrijven.

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

Bijwerken

Om de werkelijke locatie van gegevens te controleren, kan een eenvoudige test dit aantonen:

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

De %%physloc%% pseudo-kolom toont de werkelijke fysieke locatie van de rij, in mijn geval was het pagina 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 kolomwaarden behalve de TEXT en NTEXT werden inline opgeslagen, inclusief de MAX-typen.
Na het wijzigen van de tabelopties en het invoegen van een nieuwe rij (sp_tableoption heeft geen invloed op bestaande rijen), werden de MAX-typen naar hun eigen opslag verplaatst:

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

Merk op hoe de kolommen m_a en nm_a nu een tekstaanwijzer zijn in de LOB-toewijzingseenheid:

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)                    

Voor de volledigheid kunnen we ook een van de niet-max velden uit de rij forceren:

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

Merk op hoe de v_a-kolom wordt opgeslagen in de Row-Overflow-opslag:

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) 

Dus, zoals anderen al hebben opgemerkt, worden de MAX-typen standaard inline opgeslagen, als ze passen. Voor veel DW-projecten zou dit onaanvaardbaar zijn omdat de typische DW-belastingen moeten scannen of op zijn minst een bereikscan moeten maken, dus de sp_tableoption ..., 'large value types out of row', '1' zou gebruikt moeten worden. Merk op dat dit geen invloed heeft op bestaande rijen, in mijn test zelfs niet bij het opnieuw opbouwen van de index , dus de optie moet vroeg worden ingeschakeld.

Voor de meeste belastingen van het OLTP-type is het feit dat MAX-typen indien mogelijk inline worden opgeslagen, eigenlijk een voordeel, aangezien het OLTP-toegangspatroon zoeken is en de rijbreedte er weinig invloed op heeft.

Toch wat betreft de oorspronkelijke vraag:aparte tabel is niet nodig. De large value types out of row inschakelen optie behaalt hetzelfde resultaat tegen gratis kosten voor ontwikkeling/test.



  1. MySQL Workbench-zelfstudie - Een uitgebreide gids voor de RDBMS-tool

  2. Vergelijking van hoge beschikbaarheid van database - MySQL / MariaDB-replicatie versus Oracle Data Guard

  3. Beperking van de WHERE col IN (...) voorwaarde

  4. Test voor null in functie met verschillende parameters