Lách
Khi thực hiện một số thử nghiệm trên các cột thưa thớt, như bạn làm, có một nhược điểm về hiệu suất mà tôi muốn biết nguyên nhân trực tiếp.
DDL
Tôi đã tạo hai bảng giống hệt nhau, một bảng có 4 cột thưa và một cột không có cột thưa.
--Non Sparse columns table & NC index
CREATE TABLE dbo.nonsparse( ID INT IDENTITY(1,1) PRIMARY KEY NOT NULL,
charval char(20) NULL,
varcharval varchar(20) NULL,
intval int NULL,
bigintval bigint NULL
);
CREATE INDEX IX_Nonsparse_intval_varcharval
ON dbo.nonsparse(intval,varcharval)
INCLUDE(bigintval,charval);
-- sparse columns table & NC index
CREATE TABLE dbo.sparse( ID INT IDENTITY(1,1) PRIMARY KEY NOT NULL,
charval char(20) SPARSE NULL ,
varcharval varchar(20) SPARSE NULL,
intval int SPARSE NULL,
bigintval bigint SPARSE NULL
);
CREATE INDEX IX_sparse_intval_varcharval
ON dbo.sparse(intval,varcharval)
INCLUDE(bigintval,charval);
DML
Sau đó tôi đã chèn khoảng 2540 giá trị NON-NULL vào cả hai.
INSERT INTO dbo.nonsparse WITH(TABLOCK) (charval, varcharval,intval,bigintval)
SELECT 'Val1','Val2',20,19
FROM MASTER..spt_values;
INSERT INTO dbo.sparse WITH(TABLOCK) (charval, varcharval,intval,bigintval)
SELECT 'Val1','Val2',20,19
FROM MASTER..spt_values;
Sau đó, tôi đã chèn các giá trị NULL 1M vào cả hai bảng
INSERT INTO dbo.nonsparse WITH(TABLOCK) (charval, varcharval,intval,bigintval)
SELECT TOP(1000000) NULL,NULL,NULL,NULL
FROM MASTER..spt_values spt1
CROSS APPLY MASTER..spt_values spt2;
INSERT INTO dbo.sparse WITH(TABLOCK) (charval, varcharval,intval,bigintval)
SELECT TOP(1000000) NULL,NULL,NULL,NULL
FROM MASTER..spt_values spt1
CROSS APPLY MASTER..spt_values spt2;
Truy vấn
Thực hiện bảng không đặc biệt
Khi chạy truy vấn này hai lần trên bảng không được tạo mới:
SET STATISTICS IO, TIME ON;
SELECT * FROM dbo.nonsparse
WHERE 1= (SELECT 1) -- force non trivial plan
OPTION(RECOMPILE,MAXDOP 1);
Các bài đọc logic hiển thị 5257 trang
(1002540 rows affected)
Table 'nonsparse'. Scan count 1, logical reads 5257, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Và thời gian cpu là 343 ms
SQL Server Execution Times:
CPU time = 343 ms, elapsed time = 3850 ms.
thực hiện bảng thưa thớt
Chạy cùng một truy vấn hai lần trên bảng thưa thớt:
SELECT * FROM dbo.sparse
WHERE 1= (SELECT 1) -- force non trivial plan
OPTION(RECOMPILE,MAXDOP 1);
Số đọc thấp hơn, 1763
(1002540 rows affected)
Table 'sparse'. Scan count 1, logical reads 1763, physical reads 3, read-ahead reads 1759, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Nhưng thời gian cpu cao hơn, 547 ms .
SQL Server Execution Times:
CPU time = 547 ms, elapsed time = 2406 ms.
Kế hoạch thực hiện bảng thưa thớt
kế hoạch thực hiện bảng không thưa thớt
Câu hỏi
Câu hỏi gốc
Vì các giá trị NULL không được lưu trữ trực tiếp trong các cột thưa thớt, nên việc tăng thời gian cpu có thể là do trả về các giá trị NULL dưới dạng tập kết quả không? Hay chỉ đơn giản là hành vi như được ghi chú trong tài liệu ?
Các cột thưa thớt làm giảm các yêu cầu không gian cho các giá trị null với chi phí cao hơn để lấy các giá trị không hoàn chỉnh
Hoặc là chi phí chỉ liên quan đến đọc và lưu trữ được sử dụng?
Ngay cả khi chạy ssms với kết quả loại bỏ sau tùy chọn thực thi, thời gian cpu của lựa chọn thưa thớt vẫn cao hơn (407 ms) so với không thưa thớt (219 ms).
BIÊN TẬP
Nó có thể là chi phí chung của các giá trị không null, ngay cả khi chỉ có 2540 hiện tại, nhưng tôi vẫn không bị thuyết phục.
Điều này có vẻ là về hiệu suất tương tự, nhưng yếu tố thưa thớt đã bị mất.
CREATE INDEX IX_Filtered
ON dbo.sparse(charval,varcharval,intval,bigintval)
WHERE charval IS NULL
AND varcharval IS NULL
AND intval IS NULL
AND bigintval IS NULL;
CREATE INDEX IX_Filtered
ON dbo.nonsparse(charval,varcharval,intval,bigintval)
WHERE charval IS NULL
AND varcharval IS NULL
AND intval IS NULL
AND bigintval IS NULL;
SET STATISTICS IO, TIME ON;
SELECT charval,varcharval,intval,bigintval FROM dbo.sparse WITH(INDEX(IX_Filtered))
WHERE charval IS NULL AND varcharval IS NULL
AND intval IS NULL
AND bigintval IS NULL
OPTION(RECOMPILE,MAXDOP 1);
SELECT charval,varcharval,intval,bigintval
FROM dbo.nonsparse WITH(INDEX(IX_Filtered))
WHERE charval IS NULL AND
varcharval IS NULL
AND intval IS NULL
AND bigintval IS NULL
OPTION(RECOMPILE,MAXDOP 1);
Có vẻ như có cùng thời gian thực hiện:
SQL Server Execution Times:
CPU time = 297 ms, elapsed time = 292 ms.
SQL Server Execution Times:
CPU time = 281 ms, elapsed time = 319 ms.
Nhưng tại sao các logic đọc cùng một số tiền bây giờ? Không phải chỉ mục được lọc cho cột thưa thớt không lưu trữ bất cứ thứ gì ngoại trừ trường ID được bao gồm và một số trang không có dữ liệu khác?
Table 'sparse'. Scan count 1, logical reads 5785,
Table 'nonsparse'. Scan count 1, logical reads 5785
Và kích thước của cả hai chỉ số:
RowCounts Used_MB Unused_MB Total_MB
1000000 45.20 0.06 45.26
Tại sao những cái này có cùng kích thước? Là sự thưa thớt mất đi?
Cả hai kế hoạch truy vấn khi sử dụng chỉ mục được lọc
Thông tin thêm
select @@version
Microsoft SQL Server 2017 (RTM-CU16) (KB4508218) - 14.0.3223.3 (X64) Ngày 12 tháng 7 năm 2019 17:43:08 Bản quyền (C) 2017 Microsoft Corporation Developer Edition (64-bit) trên Windows Server 2012 R2 Datacenter 6.3 (Bản dựng 9600 :) (Hypervisor)
Trong khi chạy các truy vấn và chỉ chọn trường ID , thời gian cpu có thể so sánh được, với số lần đọc logic thấp hơn cho bảng thưa thớt.
Kích thước của các bảng
SchemaName TableName RowCounts Used_MB Unused_MB Total_MB
dbo nonsparse 1002540 89.54 0.10 89.64
dbo sparse 1002540 27.95 0.20 28.14
Khi buộc chỉ mục được nhóm hoặc không được bao gồm, chênh lệch thời gian cpu vẫn còn.