ในคำถามของคุณคุณให้รายละเอียดการทดสอบบางอย่างที่คุณได้เตรียมไว้ซึ่งคุณ "พิสูจน์" ว่าตัวเลือกเพิ่มเติมนั้นเร็วกว่าการเปรียบเทียบคอลัมน์แบบแยก ฉันสงสัยว่าวิธีการทดสอบของคุณอาจมีข้อบกพร่องหลายวิธีเนื่องจาก @gbn และ @srutzky ได้กล่าวถึง
ก่อนอื่นคุณต้องตรวจสอบให้แน่ใจว่าคุณไม่ได้ทดสอบ SQL Server Management Studio (หรือไคลเอ็นต์ใดก็ตามที่คุณใช้) ตัวอย่างเช่นหากคุณเรียกใช้SELECT *
จากตารางที่มี 3 ล้านแถวส่วนใหญ่คุณกำลังทดสอบความสามารถของ SSMS ในการดึงแถวจาก SQL Server และแสดงผลบนหน้าจอ คุณดีกว่าที่จะใช้สิ่งSELECT COUNT(1)
ที่ขัดแย้งกับความต้องการดึงแถวหลายล้านแถวทั่วทั้งเครือข่ายและแสดงบนหน้าจอ
ประการที่สองคุณต้องระวังแคชข้อมูลของ SQL Server โดยทั่วไปเราทดสอบความเร็วในการอ่านข้อมูลจากหน่วยเก็บข้อมูลและประมวลผลข้อมูลนั้นจาก cold-cache (เช่นบัฟเฟอร์ของ SQL Server ว่างเปล่า) ในบางครั้งมันสมเหตุสมผลที่จะทำการทดสอบทั้งหมดด้วย warm-cache แต่คุณต้องเข้าใกล้การทดสอบของคุณอย่างชัดเจนโดยคำนึงถึงสิ่งนั้น
สำหรับการทดสอบ cold-cache คุณจำเป็นต้องเรียกใช้CHECKPOINT
และDBCC DROPCLEANBUFFERS
ก่อนการทดสอบแต่ละครั้ง
สำหรับการทดสอบที่คุณถามเกี่ยวกับคำถามของคุณฉันได้สร้างแบบทดสอบดังต่อไปนี้:
IF COALESCE(OBJECT_ID('tempdb..#SomeTest'), 0) <> 0
BEGIN
DROP TABLE #SomeTest;
END
CREATE TABLE #SomeTest
(
TestID INT NOT NULL
PRIMARY KEY
IDENTITY(1,1)
, A INT NOT NULL
, B FLOAT NOT NULL
, C MONEY NOT NULL
, D BIGINT NOT NULL
);
INSERT INTO #SomeTest (A, B, C, D)
SELECT o1.object_id, o2.object_id, o3.object_id, o4.object_id
FROM sys.objects o1
, sys.objects o2
, sys.objects o3
, sys.objects o4;
SELECT COUNT(1)
FROM #SomeTest;
ส่งคืนจำนวน 260,144,641 ในเครื่องของฉัน
เพื่อทดสอบวิธี "การเพิ่ม" ฉันเรียกใช้:
CHECKPOINT 5;
DBCC FREEPROCCACHE;
DBCC DROPCLEANBUFFERS;
SET STATISTICS IO, TIME ON;
GO
SELECT COUNT(1)
FROM #SomeTest st
WHERE (st.A + st.B + st.C + st.D) = 0;
GO
SET STATISTICS IO, TIME OFF;
แท็บข้อความแสดง:
ตาราง '#SomeTest' จำนวนการสแกน 3, การอ่านเชิงตรรกะ 1322661, การอ่านทางกายภาพ 0, การอ่านล่วงหน้าอ่าน 1313877, lob การอ่านเชิงตรรกะ 0, lob การอ่านทางกายภาพ 0, lob การอ่านล่วงหน้าอ่าน 0
เวลาดำเนินการของ SQL Server: เวลา CPU = 49047 ms, เวลาที่ผ่านไป = 173451 ms
สำหรับการทดสอบ "คอลัมน์แยก":
CHECKPOINT 5;
DBCC FREEPROCCACHE;
DBCC DROPCLEANBUFFERS;
SET STATISTICS IO, TIME ON;
GO
SELECT COUNT(1)
FROM #SomeTest st
WHERE st.A = 0
AND st.B = 0
AND st.C = 0
AND st.D = 0;
GO
SET STATISTICS IO, TIME OFF;
อีกครั้งจากแท็บข้อความ:
ตาราง '#SomeTest' จำนวนการสแกน 3, อ่านโลจิคัล 1322661, อ่านฟิสิคัล 0, อ่านล่วงหน้าอ่าน 1322661, ล๊อบอ่านตรรกะ 0, lob อ่านฟิสิคัล 0, lob อ่านล่วงหน้าอ่าน 0
เวลาดำเนินการของ SQL Server: เวลา CPU = 8938 ms, เวลาที่ผ่านไป = 162581 ms
จากสถิติด้านบนคุณจะเห็นตัวแปรที่สองโดยคอลัมน์แบบแยกเมื่อเทียบกับ 0 เวลาที่ผ่านไปจะสั้นลงประมาณ 10 วินาทีและเวลา CPU จะลดลงประมาณ 6 เท่า ระยะเวลานานในการทดสอบของฉันข้างต้นส่วนใหญ่เป็นผลมาจากการอ่านแถวจำนวนมากจากดิสก์ หากคุณลดจำนวนแถวลงเหลือ 3 ล้านคุณจะเห็นว่าอัตราส่วนยังคงเท่าเดิม แต่เวลาที่ผ่านไปลดลงอย่างเห็นได้ชัดเนื่องจากดิสก์ I / O มีผลกระทบน้อยกว่ามาก
ด้วยวิธีการ "เพิ่มเติม":
ตาราง '#SomeTest' จำนวนการสแกน 3, การอ่านโลจิคัล 15255, การอ่านทางกายภาพ 0, การอ่านล่วงหน้าอ่าน 0, lob โลจิคัลการอ่าน 0, lob การอ่านทางกายภาพ 0, lob การอ่านล่วงหน้าอ่าน 0
เวลาดำเนินการของ SQL Server: เวลา CPU = 499 ms, เวลาที่ผ่านไป = 256 ms
ด้วยวิธี "คอลัมน์แยก":
ตาราง '#SomeTest' จำนวนการสแกน 3, การอ่านโลจิคัล 15255, การอ่านทางกายภาพ 0, การอ่านล่วงหน้าอ่าน 0, lob โลจิคัลการอ่าน 0, lob การอ่านทางกายภาพ 0, lob การอ่านล่วงหน้าอ่าน 0
เวลาดำเนินการของ SQL Server: เวลา CPU = 94 ms, เวลาที่ผ่านไป = 53 ms
อะไรจะสร้างความแตกต่างที่ยิ่งใหญ่สำหรับการทดสอบนี้ ดัชนีที่เหมาะสมเช่น:
CREATE INDEX IX_SomeTest ON #SomeTest(A, B, C, D);
วิธีการ "เพิ่มเติม":
ตาราง '#SomeTest' จำนวนการสแกน 3, อ่านลอจิคัล 14235, อ่านฟิสิคัล 0, อ่านล่วงหน้าอ่าน 0, lob อ่านโลจิคัล 0, lob อ่านฟิสิคัล 0, lob อ่านล่วงหน้าอ่าน 0
เวลาดำเนินการของ SQL Server: เวลา CPU = 546 ms, เวลาที่ผ่านไป = 314 ms
วิธีการ "คอลัมน์แยก":
ตาราง '#SomeTest' จำนวนการสแกน 1, การอ่านเชิงตรรกะ 3, การอ่านทางกายภาพ 0, การอ่านล่วงหน้าอ่าน 0, lob ตรรกะอ่าน 0, lob การอ่านทางกายภาพ 0, lob การอ่านล่วงหน้าอ่าน 0
เวลาดำเนินการของ SQL Server: เวลา CPU = 0 ms, เวลาที่ผ่านไป = 0 ms
แผนการดำเนินการสำหรับแต่ละแบบสอบถาม (ด้วยดัชนีด้านบนแทน) ค่อนข้างบอก
วิธีการ "เพิ่มเติม" ซึ่งจะต้องทำการสแกนดัชนีทั้งหมด:
และวิธีการ "คอลัมน์แยก" ซึ่งสามารถค้นหาในแถวแรกของดัชนีที่คอลัมน์ดัชนีนำA
เป็นศูนย์: