Sqlserver
 sql >> Teknologi Basis Data >  >> RDS >> Sqlserver

Haruskah saya menggunakan kolom varchar(max) sebaris atau menyimpannya di tabel terpisah?

Tetap sebaris. Di bawah penutup SQL Server sudah menyimpan kolom MAX di 'unit alokasi' terpisah sejak SQL 2005. Lihat Tabel dan Organisasi Indeks. Ini berlaku persis sama dengan menjaga kolom MAX di tabelnya sendiri, tetapi tanpa kerugian dari melakukannya secara eksplisit.

Memiliki tabel eksplisit sebenarnya akan lebih lambat (karena batasan kunci asing) dan menggunakan lebih banyak ruang (karena duplikasi DetaiID). Belum lagi membutuhkan lebih banyak kode, dan bug diperkenalkan oleh... menulis kode.

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

Perbarui

Untuk memeriksa lokasi data yang sebenarnya, tes sederhana dapat menunjukkannya:

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%% kolom semu akan menunjukkan lokasi fisik sebenarnya dari baris tersebut, dalam kasus saya ini adalah halaman 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)   

Semua nilai kolom kecuali TEXT dan NTEXT disimpan inline, termasuk tipe MAX.
Setelah mengubah opsi tabel dan menyisipkan baris baru (sp_tableoption tidak memengaruhi baris yang ada), tipe MAX dikeluarkan ke penyimpanannya sendiri:

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

Perhatikan bagaimana kolom m_a dan nm_a sekarang menjadi Textpointer ke dalam unit alokasi 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)                    

Demi kelengkapan, kami juga dapat memaksa salah satu bidang non-maks keluar dari baris:

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

Perhatikan bagaimana kolom v_a disimpan di penyimpanan 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) 

Jadi, seperti yang telah dikomentari orang lain, tipe MAX disimpan sebaris secara default, jika cocok. Untuk banyak proyek DW, ini tidak dapat diterima karena beban DW tipikal harus dipindai atau setidaknya pemindaian rentang, jadi sp_tableoption ..., 'large value types out of row', '1' seharusnya digunakan. Perhatikan bahwa ini tidak memengaruhi baris yang ada, dalam pengujian saya bahkan pada pembangunan kembali indeks , jadi opsi harus diaktifkan lebih awal.

Untuk sebagian besar jenis OLTP memuat meskipun fakta bahwa jenis MAX disimpan sebaris jika memungkinkan sebenarnya merupakan keuntungan, karena pola akses OLTP adalah untuk mencari dan lebar baris tidak banyak mempengaruhinya.

Tidak kurang, mengenai pertanyaan awal:tabel terpisah tidak diperlukan. Mengaktifkan large value types out of row opsi mencapai hasil yang sama dengan biaya gratis untuk pengembangan/pengujian.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Bagaimana cara menghitung total jam perjalanan antara kota x dan y dan sebaliknya

  2. Nilai NULL di dalam klausa NOT IN

  3. Ikhtisar Pernyataan PRINT di SQL Server

  4. Temukan Kolom Partisi untuk Tabel yang Dipartisi di SQL Server (T-SQL)

  5. Mengapa kueri Microsoft SQL Server 2012 membutuhkan waktu beberapa menit dari JDBC 4.0 tetapi detik di Management Studio?