ฉันมีแบบสอบถามที่วิ่งใน800 มิลลิวินาทีใน SQL Server 2012และใช้เวลาประมาณ170 วินาทีใน SQL Server 2014 ฉันคิดว่าฉันได้ จำกัด เรื่องนี้ให้แคบลงเพื่อประเมินความน่าจะเป็นของRow Count Spool
ผู้ให้บริการ ฉันได้อ่านเกี่ยวกับตัวดำเนินการสปูลแล้ว (เช่นที่นี่และที่นี่ ) แต่ฉันยังคงมีปัญหาในการทำความเข้าใจบางสิ่ง:
- เหตุใดแบบสอบถามนี้จึงต้องการ
Row Count Spool
ผู้ดำเนินการ ฉันไม่คิดว่ามันจำเป็นสำหรับความถูกต้องดังนั้นสิ่งที่พยายามเพิ่มประสิทธิภาพโดยเฉพาะคืออะไร? - เหตุใด SQL Server จึงประมาณว่าการเข้าร่วมกับ
Row Count Spool
ผู้ดำเนินการลบแถวทั้งหมดออก - นี่เป็นข้อบกพร่องใน SQL Server 2014 หรือไม่ ถ้าเป็นเช่นนั้นฉันจะยื่นในการเชื่อมต่อ แต่ฉันต้องการความเข้าใจที่ลึกซึ้งยิ่งขึ้นก่อน
หมายเหตุ: ฉันสามารถเขียนแบบสอบถามอีกครั้งเป็นLEFT JOIN
หรือเพิ่มดัชนีลงในตารางเพื่อให้ได้ประสิทธิภาพที่ยอมรับได้ทั้งใน SQL Server 2012 และ SQL Server 2014 ดังนั้นคำถามนี้เกี่ยวกับการทำความเข้าใจแบบสอบถามเฉพาะและแผนในเชิงลึกมากขึ้น วิธีวลีที่ค้นหาแตกต่างกัน
แบบสอบถามช้า
ดูPastebin นี้สำหรับสคริปต์ทดสอบฉบับเต็ม นี่คือคำถามทดสอบเฉพาะที่ฉันกำลังดู:
-- Prune any existing customers from the set of potential new customers
-- This query is much slower than expected in SQL Server 2014
SELECT *
FROM #potentialNewCustomers -- 10K rows
WHERE cust_nbr NOT IN (
SELECT cust_nbr
FROM #existingCustomers -- 1MM rows
)
SQL Server 2014: แผนแบบสอบถามโดยประมาณ
SQL Server เชื่อว่าการLeft Anti Semi Join
ถึงRow Count Spool
จะกรอง 10,000 แถวลงไปที่ 1 แถว ด้วยเหตุนี้มันเลือกสำหรับต่อมาเข้าร่วมLOOP JOIN
#existingCustomers
SQL Server 2014: แผนแบบสอบถามจริง
ตามที่คาดไว้ (โดยทุกคนยกเว้น SQL Server!), Row Count Spool
ไม่ได้ลบแถวใด ๆ ดังนั้นเราจึงวนซ้ำ 10,000 ครั้งเมื่อ SQL Server คาดว่าจะวนซ้ำเพียงครั้งเดียว
SQL Server 2012: แผนแบบสอบถามโดยประมาณ
เมื่อใช้ SQL Server 2012 (หรือOPTION (QUERYTRACEON 9481)
ใน SQL Server 2014) Row Count Spool
จะไม่ลดจำนวนแถวโดยประมาณและเลือกการเข้าร่วมแฮชซึ่งส่งผลให้มีการวางแผนที่ดีขึ้น
ซ้ายเข้าร่วมใหม่เขียน
สำหรับการอ้างอิงต่อไปนี้เป็นวิธีที่ฉันอาจเขียนแบบสอบถามอีกครั้งเพื่อให้ได้ประสิทธิภาพที่ดีใน SQL Server 2012, 2014 และ 2016 ทั้งหมดอย่างไรก็ตามฉันยังคงสนใจในพฤติกรรมเฉพาะของแบบสอบถามด้านบนและไม่ว่าจะเป็น เป็นบั๊กในเครื่องมือประมาณการ Cardinality ใหม่ของ SQL Server 2014
-- Re-writing with LEFT JOIN yields much better performance in 2012/2014/2016
SELECT n.*
FROM #potentialNewCustomers n
LEFT JOIN (SELECT 1 AS test, cust_nbr FROM #existingCustomers) c
ON c.cust_nbr = n.cust_nbr
WHERE c.test IS NULL