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.