sql >> Databasteknik >  >> RDS >> Sqlserver

Ska jag använda en inline varchar(max) kolumn eller lagra den i en separat tabell?

Håll det inline. Under täcket lagrar SQL Server redan MAX-kolumnerna i en separat 'allokeringsenhet' sedan SQL 2005. Se Tabell- och Indexorganisation. Detta är i själva verket exakt samma sak som att behålla MAX-kolumnen i sin egen tabell, men utan någon nackdel med att uttryckligen göra det.

Att ha en explicit tabell skulle faktiskt vara både långsammare (på grund av den främmande nyckeln) och konsumera mer utrymme (på grund av DetaiID-dupliceringen). För att inte tala om att det kräver mer kod, och buggar introduceras genom att... skriva kod.

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

Uppdatera

För att kontrollera den faktiska platsen för data kan ett enkelt test visa det:

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

%%physloc%% pseudokolumnen visar den faktiska fysiska platsen för raden, i mitt fall var det sidan 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)   

Alla kolumnvärden utom TEXT och NTEXT lagrades inline, inklusive MAX-typerna.
Efter att ha ändrat tabellalternativen och infogat en ny rad (sp_tableoption påverkar inte befintliga rader), vräktes MAX-typerna till sin egen lagring:

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

Notera hur kolumnerna m_a och nm_a nu är en textpekare i LOB-tilldelningsenheten:

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)                    

För kompletteringens skull kan vi också tvinga det ena av de icke-maxfält ut ur rad:

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

Notera hur v_a-kolumnen lagras i Row-Overflow-lagringen:

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) 

Så, som andra redan har kommenterat, lagras MAX-typerna inline som standard, om de passar. För många DW-projekt skulle detta vara oacceptabelt eftersom de typiska DW-belastningarna måste skanna eller åtminstone intervallskanning, så sp_tableoption ..., 'large value types out of row', '1' borde användas. Observera att detta inte påverkar befintliga rader, i mitt test inte ens vid ombyggnad av index , så alternativet måste aktiveras tidigt.

För de flesta belastningar av OLTP-typ är dock det faktum att MAX-typer lagras inline om möjligt faktiskt en fördel, eftersom OLTP-åtkomstmönstret är att söka och radbredden har liten inverkan på det.

Icke desto mindre när det gäller den ursprungliga frågan:separat tabell är inte nödvändig. Aktivera large value types out of row option uppnår samma resultat till en gratis kostnad för utveckling/test.



  1. Lägg till en främmande nyckel till en befintlig tabell i SQLite

  2. Översikt över datakomprimering i SQL Server

  3. Är du sorterad? Tips angående T-SQL-fönsterbeställning

  4. Hur genererar man hela DDL för ett Oracle-schema (skriptbart)?