คอลัมน์ที่กระจัดกระจายเวลาซีพียูและดัชนีที่กรอง


10

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

เมื่อบังคับให้ดัชนีแบบคลัสเตอร์หรือแบบไม่คลัสเตอร์ความแตกต่างของเวลาซีพียูจะยังคงอยู่


1
คุณสามารถรับแผนสำหรับแบบสอบถามหลังการแก้ไขได้หรือไม่
George.Palacios

1
@ George.Palacios เพิ่มพวกเขา :)
Randi Vertongen

คำตอบ:


6

หรือเป็นเพียงพฤติกรรมตามที่ระบุไว้ในเอกสารประกอบ?

น่าจะเป็นแบบนั้น. "โอเวอร์เฮด" ที่กล่าวถึงในเอกสารดูเหมือนจะเป็นโอเวอร์เฮดของ CPU

การทำโปรไฟล์แบบสอบถามทั้งสองแบบสอบถามแบบสอบถามกระจัดกระจายตัวอย่าง 367 ms ของ CPU ในขณะที่ non-sparse มี CPU 284 ms นั่นคือความแตกต่างจาก 83 มิลลิวินาที

สกรีนช็อตจาก Perfview แสดง CPU ทั้งหมดสำหรับเธรดที่เรียกใช้คิวรี

ส่วนใหญ่อยู่ที่ไหน

sqlmin!IndexDataSetSession::GetNextRowValuesInternalโปรไฟล์ทั้งสองมีลักษณะคล้ายกันมากจนกระทั่งพวกเขาได้รับ ณ จุดนั้นโค้ด sparse จะลงไปตามพา ธ ที่เรียกใช้sqlmin!IndexDataSetSession::GetDataLongซึ่งจะเรียกฟังก์ชั่นบางอย่างที่เกี่ยวข้องกับฟีเจอร์คอลัมน์ sparse ( HasSparseVector, StoreColumnValue) และเพิ่มขึ้นเป็น (42 + 11 =) 53 ms

สกรีนช็อตของความแตกต่างของ CPU สำหรับคอลัมน์กระจัดกระจาย

ทำไมขนาดเท่ากัน? ความกระจัดกระจายหายไปหรือไม่

ใช่ดูเหมือนว่าการเพิ่มประสิทธิภาพการจัดเก็บ sparse ไม่ได้ส่งไปยังดัชนี nonclustered เมื่อคอลัมน์ sparse ใช้เป็นคีย์ดัชนี ดังนั้นคอลัมน์คีย์ดัชนีที่ไม่คลัสเตอร์จะใช้ขนาดเต็มโดยไม่คำนึงถึงความเบาบาง แต่คอลัมน์ที่รวมไว้นั้นจะใช้พื้นที่เป็นศูนย์ถ้าพวกมันกระจัดกระจายและ NULL

ดูที่DBCC PAGEผลลัพธ์จากหน้าดัชนีคลัสเตอร์ที่มีคอลัมน์กระจัดกระจายมูลค่า NULL ฉันจะเห็นว่าความยาวของบันทึกเป็น 11 (4 สำหรับ ID + 7 สำหรับค่าใช้จ่ายต่อการบันทึกมาตรฐาน):

Record Type = PRIMARY_RECORD        Record Attributes =  NULL_BITMAP    Record Size = 11

สำหรับดัชนีที่กรองแล้วเร็กคอร์ดจะเป็น 40 เสมอซึ่งเป็นผลรวมของขนาดของคอลัมน์หลักทั้งหมด (4 ไบต์ ID + 20 ไบต์ charval + 4 ไบต์ varcharval + 4 ไบต์ intval + 8 ไบต์ใหญ่ intval = 40 ไบต์)

ด้วยเหตุผลบางอย่างDBCC PAGEไม่รวมค่าใช้จ่าย 7 ไบต์ใน "ขนาดบันทึก" สำหรับบันทึกดัชนี:

Record Type = INDEX_RECORD          Record Attributes =  NULL_BITMAP    Record Size = 40

ขนาดดัชนีที่ไม่ผ่านการกรองมีขนาดเล็กกว่า (4 ไบต์ ID + 4 ไบต์ intval + 4 ไบต์ varcharval = 12 ไบต์) เนื่องจากคอลัมน์ที่กระจัดกระจายสองคอลัมน์รวมอยู่ในคอลัมน์ซึ่งจะได้รับการเพิ่มประสิทธิภาพการกระจัด:

Record Type = INDEX_RECORD          Record Attributes =  NULL_BITMAP    Record Size = 12

ฉันเดาความแตกต่างในพฤติกรรมที่สอดคล้องกับหนึ่งในข้อ จำกัด ที่ระบุไว้ในหน้าเอกสาร:

คอลัมน์กระจัดกระจายไม่สามารถเป็นส่วนหนึ่งของดัชนีคลัสเตอร์หรือดัชนีคีย์หลักที่ไม่ซ้ำกัน

พวกมันได้รับอนุญาตให้เป็นกุญแจในดัชนีที่ไม่ได้เป็นคลัสเตอร์ แต่มันไม่ได้ถูกจัดเก็บเลย


2
ทำได้ดีนี่! ขอบคุณอีกครั้ง!
Randi Vertongen
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.