Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Devo usare una colonna inline varchar(max) o memorizzarla in una tabella separata?

Tienilo in linea. Sotto le coperte SQL Server archivia già le colonne MAX in un'"unità di allocazione" separata da SQL 2005. Vedere Organizzazione di tabelle e indici. Questo in effetti è esattamente lo stesso che mantenere la colonna MAX nella propria tabella, ma senza alcuno svantaggio nel farlo esplicitamente.

Avere una tabella esplicita sarebbe in realtà sia più lento (a causa del vincolo della chiave esterna) e consumano più spazio (a causa della duplicazione di DetaiID). Per non parlare del fatto che richiede più codice e che i bug vengono introdotti... scrivendo il codice.

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

Aggiorna

Per verificare la posizione effettiva dei dati, un semplice test può mostrarlo:

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

Il %%physloc%% pseudo colonna mostrerà la posizione fisica effettiva della riga, nel mio caso era 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)   

Tutti i valori delle colonne tranne TEXT e NTEXT sono stati archiviati inline, inclusi i tipi MAX.
Dopo aver modificato le opzioni della tabella e inserito una nuova riga (sp_tableoption non ha effetto sulle righe esistenti), i tipi MAX sono stati eliminati nella propria memoria:

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

Nota come le colonne m_a e nm_a ora sono un Textpointer nell'unità di allocazione 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)                    

Per motivi di completamento possiamo anche forzare uno dei campi non max fuori dalla riga:

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

Nota come la colonna v_a viene archiviata nella memoria di overflow riga:

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) 

Quindi, come altri hanno già commentato, i tipi MAX sono memorizzati in linea per impostazione predefinita, se si adattano. Per molti progetti DW questo sarebbe inaccettabile perché i carichi DW tipici devono eseguire la scansione o almeno la scansione dell'intervallo, quindi sp_tableoption ..., 'large value types out of row', '1' dovrebbe essere usato. Nota che ciò non influisce sulle righe esistenti, nel mio test nemmeno sulla ricostruzione dell'indice , quindi l'opzione deve essere attivata in anticipo.

Per la maggior parte dei carichi di tipo OLTP, tuttavia, il fatto che i tipi MAX siano archiviati in linea, se possibile, è in realtà un vantaggio, poiché il modello di accesso OLTP è di ricerca e la larghezza della riga ha un impatto minimo su di esso.

Tuttavia, per quanto riguarda la domanda originaria:non è necessaria una tabella separata. Attivazione dei large value types out of row l'opzione ottiene lo stesso risultato a un costo gratuito per lo sviluppo/test.