Sparsing
เมื่อทำการทดสอบบางอย่างเกี่ยวกับคอลัมน์หร็อมแหร็มเช่นที่คุณทำมีความปราชัยประสิทธิภาพที่ฉันต้องการทราบสาเหตุโดยตรงของ
DDL
ฉันสร้างตารางที่เหมือนกันสองตารางโดยที่หนึ่งมี 4 คอลัมน์หร็อมแหร็มและอีกหนึ่งไม่มีคอลัมน์ที่กระจัดกระจาย
--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);
ดราก้อน
จากนั้นฉันก็แทรกค่าที่ไม่ใช่ค่า NULLประมาณ2540ลงในทั้งสองอย่าง
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;
หลังจากนั้นฉันใส่ค่า NULL 1Mลงในทั้งสองตาราง
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;
แบบสอบถาม
การเรียกใช้งานตารางที่ไม่กระจาย
เมื่อรันเคียวรีนี้สองครั้งบนตาราง nonsparse ที่สร้างขึ้นใหม่:
SET STATISTICS IO, TIME ON;
SELECT * FROM dbo.nonsparse
WHERE 1= (SELECT 1) -- force non trivial plan
OPTION(RECOMPILE,MAXDOP 1);
การอ่านแบบโลจิคัลแสดง5257หน้า
(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.
และเวลา cpu อยู่ที่343 มิลลิวินาที
SQL Server Execution Times:
CPU time = 343 ms, elapsed time = 3850 ms.
การดำเนินการตารางกระจัดกระจาย
เรียกใช้คิวรีเดียวกันสองครั้งในตารางที่กระจาย:
SELECT * FROM dbo.sparse
WHERE 1= (SELECT 1) -- force non trivial plan
OPTION(RECOMPILE,MAXDOP 1);
ค่าอ่านต่ำกว่า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.
แต่เวลาซีพียูจะสูงกว่า547 มิลลิวินาที
SQL Server Execution Times:
CPU time = 547 ms, elapsed time = 2406 ms.
แผนการดำเนินการตารางที่ไม่กระจัดกระจาย
คำถาม
คำถามเดิม
เนื่องจากค่า NULLไม่ได้ถูกเก็บไว้โดยตรงในคอลัมน์ที่กระจัดกระจายการเพิ่มขึ้นของเวลา cpu อาจเนื่องมาจากการคืนค่า NULLเป็นชุดผลลัพธ์ หรือเป็นเพียงพฤติกรรมตามที่ระบุไว้ในเอกสารประกอบ ?
คอลัมน์ที่กระจัดกระจายลดความต้องการพื้นที่สำหรับค่า Null ที่ค่าใช้จ่ายของค่าใช้จ่ายมากขึ้นเพื่อดึงค่าที่ไม่เป็นศูนย์
หรือค่าใช้จ่ายเกี่ยวข้องกับการอ่านและการจัดเก็บข้อมูลเท่านั้น
แม้ว่าจะรัน ssms ด้วยผลลัพธ์ที่ถูกทิ้งหลังจากตัวเลือกการดำเนินการเวลา cpu ของตัวเลือกการกระจัดกระจายก็สูงกว่า (407 ms) เมื่อเปรียบเทียบกับแบบไม่กระจาย (219 มิลลิวินาที)
แก้ไข
อาจเป็นค่าใช้จ่ายที่ไม่ใช่ค่าว่างแม้ว่าจะมีเพียง 2540 ในปัจจุบัน แต่ฉันก็ยังไม่เชื่อ
ดูเหมือนว่าจะเกี่ยวกับประสิทธิภาพเดียวกัน แต่ปัจจัยกระจัดกระจายหายไป
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);
ดูเหมือนว่าจะมีเวลาดำเนินการประมาณเดียวกัน:
SQL Server Execution Times:
CPU time = 297 ms, elapsed time = 292 ms.
SQL Server Execution Times:
CPU time = 281 ms, elapsed time = 319 ms.
แต่ทำไมตรรกะจึงอ่านจำนวนเท่ากัน? ดัชนีที่กรองแล้วสำหรับคอลัมน์กระจัดกระจายไม่ควรเก็บข้อมูลใด ๆ ยกเว้นฟิลด์ ID ที่รวมและหน้าอื่น ๆ ที่ไม่ใช่ข้อมูล
Table 'sparse'. Scan count 1, logical reads 5785,
Table 'nonsparse'. Scan count 1, logical reads 5785
และขนาดของดัชนีทั้งสอง:
RowCounts Used_MB Unused_MB Total_MB
1000000 45.20 0.06 45.26
ทำไมขนาดเท่ากัน? ความกระจัดกระจายหายไปหรือไม่
แผนแบบสอบถามทั้งสองเมื่อใช้ดัชนีกรอง
ข้อมูลเสริม
select @@version
Microsoft SQL Server 2017 (RTM-CU16) (KB4508218) - 14.0.3223.3 (X64) 12 ก.ค. 2019 17:43:08 ลิขสิทธิ์ (C) 2017 Microsoft Corporation นักพัฒนา Edition (64 บิต) บน Windows Server 2012 R2 Datacenter 6.3 (บิลด์) 9600:) (ไฮเปอร์ไวเซอร์)
ในขณะที่รันเคียวรีและเลือกเฉพาะฟิลด์IDเวลา cpu จะเปรียบเทียบกันได้โดยมีค่าลอจิคัลต่ำสำหรับการอ่านตาราง
ขนาดของตาราง
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
เมื่อบังคับให้ดัชนีแบบคลัสเตอร์หรือแบบไม่คลัสเตอร์ความแตกต่างของเวลาซีพียูจะยังคงอยู่