Vì varchar
dù sao phân bổ không gian linh hoạt, câu hỏi của tôi là liệu sử dụng varchar(255)
có hiệu quả hơn hay tiết kiệm nhiều không gian hơn so với sử dụng varchar(5000)
. Nếu đúng thì tại sao?
Vì varchar
dù sao phân bổ không gian linh hoạt, câu hỏi của tôi là liệu sử dụng varchar(255)
có hiệu quả hơn hay tiết kiệm nhiều không gian hơn so với sử dụng varchar(5000)
. Nếu đúng thì tại sao?
Câu trả lời:
Có, varchar(5000)
có thể tồi tệ hơn varchar(255)
nếu tất cả các giá trị sẽ phù hợp với sau này. Lý do là SQL Server sẽ ước tính kích thước dữ liệu và đến lượt nó, cấp bộ nhớ dựa trên kích thước khai báo (không thực tế ) của các cột trong bảng. Khi bạn có varchar(5000)
, nó sẽ giả sử rằng mọi giá trị dài 2.500 ký tự và bộ nhớ dự trữ dựa trên đó.
Đây là bản demo từ bài thuyết trình GroupBy gần đây của tôi về những thói quen xấu giúp bạn dễ dàng chứng minh (yêu cầu SQL Server 2016 cho một số sys.dm_exec_query_stats
cột đầu ra, nhưng vẫn có thể chứng minh được bằng SET STATISTICS TIME ON
hoặc các công cụ khác trên các phiên bản trước); nó hiển thị bộ nhớ lớn hơn và thời gian chạy dài hơn cho cùng một truy vấn đối với cùng một dữ liệu - sự khác biệt duy nhất là kích thước khai báo của các cột:
-- create three tables with different column sizes
CREATE TABLE dbo.t1(a nvarchar(32), b nvarchar(32), c nvarchar(32), d nvarchar(32));
CREATE TABLE dbo.t2(a nvarchar(4000), b nvarchar(4000), c nvarchar(4000), d nvarchar(4000));
CREATE TABLE dbo.t3(a nvarchar(max), b nvarchar(max), c nvarchar(max), d nvarchar(max));
GO -- that's important
-- Method of sample data pop : irrelevant and unimportant.
INSERT dbo.t1(a,b,c,d)
SELECT TOP (5000) LEFT(name,1), RIGHT(name,1), ABS(column_id/10), ABS(column_id%10)
FROM sys.all_columns ORDER BY object_id;
GO 100
INSERT dbo.t2(a,b,c,d) SELECT a,b,c,d FROM dbo.t1;
INSERT dbo.t3(a,b,c,d) SELECT a,b,c,d FROM dbo.t1;
GO
-- no "primed the cache in advance" tricks
DBCC FREEPROCCACHE WITH NO_INFOMSGS;
DBCC DROPCLEANBUFFERS WITH NO_INFOMSGS;
GO
-- Redundancy in query doesn't matter! Just has to create need for sorts etc.
GO
SELECT DISTINCT a,b,c,d, DENSE_RANK() OVER (PARTITION BY b,c ORDER BY d DESC)
FROM dbo.t1 GROUP BY a,b,c,d ORDER BY c,a DESC;
GO
SELECT DISTINCT a,b,c,d, DENSE_RANK() OVER (PARTITION BY b,c ORDER BY d DESC)
FROM dbo.t2 GROUP BY a,b,c,d ORDER BY c,a DESC;
GO
SELECT DISTINCT a,b,c,d, DENSE_RANK() OVER (PARTITION BY b,c ORDER BY d DESC)
FROM dbo.t3 GROUP BY a,b,c,d ORDER BY c,a DESC;
GO
SELECT [table] = N'...' + SUBSTRING(t.[text], CHARINDEX(N'FROM ', t.[text]), 12) + N'...',
s.last_dop, s.last_elapsed_time, s.last_grant_kb, s.max_ideal_grant_kb
FROM sys.dm_exec_query_stats AS s CROSS APPLY sys.dm_exec_sql_text(s.sql_handle) AS t
WHERE t.[text] LIKE N'%dbo.'+N't[1-3]%' ORDER BY t.[text];
Vì vậy, vâng, đúng kích thước cột của bạn , xin vui lòng.
Ngoài ra, tôi chạy lại các thử nghiệm với varchar (32), varchar (255), varchar (5000), varchar (8000), và varchar (max). Kết quả tương tự ( nhấp để phóng to ), mặc dù sự khác biệt giữa 32 và 255 và từ 5.000 đến 8.000, là không đáng kể:
Đây là một thử nghiệm khác với sự TOP (5000)
thay đổi cho thử nghiệm có thể tái tạo hoàn toàn hơn mà tôi đã liên tục gặp khó khăn ( bấm vào để phóng to ):
Vì vậy, ngay cả với 5.000 hàng thay vì 10.000 hàng (và có hơn 5.000 hàng trong sys.all_column ít nhất là từ SQL Server 2008 R2), một tiến trình tương đối tuyến tính được quan sát - ngay cả với cùng một dữ liệu, kích thước được xác định càng lớn của cột, càng cần nhiều bộ nhớ và thời gian để đáp ứng chính xác cùng một truy vấn (ngay cả khi nó không có ý nghĩa DISTINCT
).
varchar(450)
và varchar(255)
sẽ giống nhau? (Hoặc bất cứ điều gì dưới 4000?)
rowcount*(column_size/2)
.