Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

Czy powinienem używać wbudowanej kolumny varchar(max) czy przechowywać ją w osobnej tabeli?

Trzymaj to w linii. Pod okładkami SQL Server już od wersji SQL 2005 przechowuje kolumny MAX w oddzielnej „jednostce alokacji”. Zobacz Organizacja tabel i indeksów. W efekcie jest to dokładnie to samo, co utrzymywanie kolumny MAX we własnej tabeli, ale bez żadnych wad jawnego robienia tego.

Posiadanie wyraźnej tabeli byłoby w rzeczywistości wolniejsze (z powodu ograniczenia klucza obcego) i zużywaj więcej miejsca (z powodu duplikacji DetaiID). Nie wspominając o tym, że wymaga więcej kodu, a błędy są wprowadzane przez... pisanie kodu.

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

Aktualizacja

Aby sprawdzić rzeczywistą lokalizację danych, prosty test może to pokazać:

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%% pseudokolumna pokaże rzeczywistą fizyczną lokalizację wiersza, w moim przypadku była to strona 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)   

Wszystkie wartości kolumn oprócz TEXT i NTEXT były przechowywane w wierszu, w tym typy MAX.
Po zmianie opcji tabeli i wstawieniu nowego wiersza (sp_tableoption nie wpływa na istniejące wiersze), typy MAX zostały wyrzucone do ich własnego magazynu:

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

Zwróć uwagę, że kolumny m_a i nm_a są teraz wskaźnikiem tekstowym do jednostki alokacji 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)                    

W trosce o uzupełnienie możemy również wymusić jedno z pól niemaksymalnych z rzędu:

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

Zwróć uwagę, jak kolumna v_a jest przechowywana w pamięci Row-Overflow:

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) 

Tak więc, jak inni już skomentowali, typy MAX są domyślnie przechowywane w linii, jeśli pasują. W przypadku wielu projektów DW byłoby to niedopuszczalne, ponieważ typowe obciążenia DW muszą być skanowane lub przynajmniej skanowane w zakresie, więc sp_tableoption ..., 'large value types out of row', '1' powinien być używany. Zauważ, że nie ma to wpływu na istniejące wiersze, w moim teście nawet przy przebudowie indeksu , więc opcja musi być włączona wcześniej.

W przypadku większości obciążeń typu OLTP fakt, że typy MAX są przechowywane, jeśli to możliwe, jest w rzeczywistości zaletą, ponieważ wzorzec dostępu OLTP polega na wyszukiwaniu, a szerokość wiersza ma na to niewielki wpływ.

Niemniej jednak w odniesieniu do pierwotnego pytania:oddzielna tabela nie jest konieczna. Włączanie large value types out of row opcja pozwala uzyskać ten sam wynik za darmo na rozwój/testowanie.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. SQL NOT IN nie działa

  2. Jaka jest różnica między Scope_Identity(), Identity(), @@Identity i Ident_Current()?

  3. Instrukcja SQL CASE

  4. Limit czasu połączenia dla serwera SQL

  5. Przedstawiamy pierwszą na świecie platformę SaaS zapewniającą dogłębną diagnostykę dla hybrydowych środowisk SQL Server