Sqlserver
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Sqlserver

Tôi nên sử dụng cột varchar (max) nội tuyến hay lưu trữ nó trong một bảng riêng?

Giữ nó nội tuyến. Dưới vỏ bọc, SQL Server đã lưu trữ các cột MAX trong một 'đơn vị cấp phát' riêng biệt kể từ SQL 2005. Xem Tổ chức Bảng và Chỉ mục. Thực tế, điều này giống hệt như việc giữ cột MAX trong bảng của chính nó, nhưng sẽ có bất kỳ nhược điểm nào của việc làm như vậy một cách rõ ràng.

Việc có một bảng rõ ràng thực sự sẽ chậm hơn (do ràng buộc khóa ngoài) và tiêu tốn nhiều dung lượng hơn (vì sự trùng lặp DetaiID). Chưa kể rằng nó đòi hỏi nhiều mã hơn và các lỗi được tạo ra bằng cách ... viết mã.

văn bản thay thế http://i.msdn.microsoft.com/ms189051.3be61595-d405-4b30-9794-755842d7db7e(en-us,SQL.100).gif

Cập nhật

Để kiểm tra vị trí thực tế của dữ liệu, một thử nghiệm đơn giản có thể cho thấy nó:

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%% cột giả sẽ hiển thị vị trí thực tế của hàng, trong trường hợp của tôi, đó là trang 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)   

Tất cả các giá trị cột trừ TEXT và NTEXT đã được lưu trữ nội tuyến, bao gồm cả các loại MAX.
Sau khi thay đổi các tùy chọn bảng và chèn một hàng mới (sp_tableoption không ảnh hưởng đến các hàng hiện có), các loại MAX đã được chuyển vào bộ nhớ của riêng chúng:

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

Lưu ý cách các cột m_a và nm_a hiện là một Textpointer trong đơn vị phân bổ 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)                    

Để hoàn thành, chúng ta cũng có thể buộc một trong các trường không phải max ra khỏi hàng:

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

Lưu ý cách cột v_a được lưu trữ trong bộ nhớ Hàng-Tràn:

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) 

Vì vậy, như những người khác đã nhận xét, các loại MAX được lưu trữ nội tuyến theo mặc định, nếu chúng phù hợp. Đối với nhiều dự án DW, điều này sẽ không được chấp nhận vì các tải DW điển hình phải quét hoặc ít nhất là quét theo phạm vi, vì vậy sp_tableoption ..., 'large value types out of row', '1' nên được sử dụng. Lưu ý rằng điều này không ảnh hưởng đến các hàng hiện có, trong thử nghiệm của tôi thậm chí không ảnh hưởng đến việc xây dựng lại chỉ mục , vì vậy tùy chọn này phải được bật sớm.

Đối với hầu hết các tải loại OLTP, mặc dù thực tế là các loại MAX được lưu trữ nội tuyến nếu có thể thực sự là một lợi thế, vì mẫu truy cập OLTP là để tìm kiếm và độ rộng hàng ít ảnh hưởng đến nó.

Không kém, liên quan đến câu hỏi ban đầu:bảng riêng là không cần thiết. Bật large value types out of row tùy chọn đạt được kết quả tương tự với chi phí phát triển / thử nghiệm miễn phí.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Tại sao các hàm có giá trị vô hướng của SQL Server hoạt động chậm hơn?

  2. NOLOCK (gợi ý Máy chủ Sql) có phải là phương pháp không tốt không?

  3. Làm cách nào để chuyển XML từ C # sang một thủ tục được lưu trữ trong SQL Server 2008?

  4. Làm cách nào để lấy danh sách tất cả các bảng trong cơ sở dữ liệu bằng TSQL?

  5. Kiểm tra xem bảng tạm thời có tồn tại hay không và xóa nếu bảng đó tồn tại trước khi tạo bảng tạm thời