เหตุใดดัชนีของฉันจึงสามารถค้นหาประมาณจำนวนแถวที่ถูกต้องและตัวดำเนินการเรียงลำดับไม่ได้


11

ฉันมีแบบสอบถามที่ใช้ฟังก์ชันในเพรดิเคตบางอย่างเช่นนี้:

commentType = 'EL'
AND commentDateTime >= DATEADD(month,datediff(month,0,getdate()) - 13,0)

ฉันมีดัชนีตัวกรองใน commentType ที่มีแถว 40K และเมื่อฉันเรียกใช้แบบสอบถามจำนวนแถวโดยประมาณสำหรับดัชนี Seek นั้นแม่นยำมาก (ประมาณ 11K) แต่สำหรับขั้นตอนต่อไป (ตัวดำเนินการเรียงลำดับ) จะไม่สนใจสถิติและ เพียงประมาณจำนวนแถวทั้งหมดในดัชนีที่กรอง

ทำไมสิ่งนี้จึงเกิดขึ้น ฉันรู้พื้นฐานเกี่ยวกับการsargabilityและฉันทดสอบเพียงเพื่อความมีสติแทน dateadd ตามวันที่จริง (2014-01-01) และ voila ... การเรียงลำดับเริ่มเดาจำนวนแถวอย่างถูกต้อง ...

เหตุใดสิ่งนี้จึงเกิดขึ้นและฉันจะแก้ไขได้อย่างไร ฉันไม่สามารถผ่านวันที่แน่นอน ...


DATEADD(month,datediff(month,0,getdate()) - 13,0)ไม่สมเหตุสมผลสำหรับฉัน คุณพยายามทำอะไรกับสิ่งนี้ มันอาจจะปรับปรุง / ประยุกต์?
Daniel Hutmacher

2
@Daniel นั่นคือจุดเริ่มต้นของเดือนที่ผ่านมา 13 เดือน
Aaron Bertrand

1
นอกจากนี้โปรดแก้ไขคำถามของคุณเพื่อสะท้อนถึงเวอร์ชันของ SQL Server (?) ที่คุณใช้งานอยู่ ใช้แท็กสำหรับสิ่งนั้น
Daniel Hutmacher

คุณลองDATEADD(month, -13, DATEADD(day, 1-DATEPART(day, SYSDATETIME()))และดูว่ามีความแตกต่างหรือไม่?
Daniel Hutmacher

หากคุณมีดัชนีที่ไม่ผ่านการกรอง(commentType, commentDate)มันจะทำงานได้ดีขึ้นหรือไม่ เป็นเพียงดัชนีที่กรองบางครั้งสามารถรายงานประมาณการผิดที่จุดต่าง ๆ ในแผน การคาดคะเนดูเหมือนจะหมดไปด้วยการรายงานจำนวนทั้งหมดในดัชนีที่กรองแล้ว แต่ที่จริงแล้วแผนกำลังแสดงผิด
Rob Farley

คำตอบ:


9

ฉันเชื่อว่าการประเมินของคุณผิดเนื่องจากข้อผิดพลาดของตัวประมาณที่แลกเปลี่ยนอาร์กิวเมนต์ DATEDIFF สองรายการ ฉันพูดถึงเรื่องนี้ที่นี่:

วิธีแก้ปัญหาคือการคำนวณวันแรกของ 13 เดือนที่ผ่านมาโดยไม่ใช้ DATEDIFF (2008+):

DATEADD(MONTH, -13, DATEADD(DAY, 1-DATEPART(DAY,GETDATE()), CONVERT(DATE, GETDATE()));

ฉันไม่ได้ในเชิงบวกว่าจะอยู่ที่การประมาณการ (ฉันไม่ได้ทดสอบกับดัชนีกรองและผมไม่แน่ใจว่าสิ่งที่จัดเรียงเป็นจริงทำหรือทำไมมันมีการประเมินที่แตกต่างกันได้โดยไม่ต้องวางแผนและ / หรือส่วนที่เหลือของแบบสอบถาม )

การแก้ไขที่ Microsoft แนะนำคือการใช้ TF 4199 แต่ฉันไม่แน่ใจว่าเป็นสิ่งที่คุณต้องทำที่นี่:

ตัวเลือกอื่นคือให้แน่ใจว่าคุณใช้ SP / CU ล่าสุดที่แน่นอนสำหรับ SQL Server รุ่นใดก็ตามที่คุณใช้เนื่องจากพวกเขาอ้างว่าได้รับการแก้ไขในบทความ KB ต่อไปนี้ (แม้ว่านี่จะยังต้องใช้ TF 4199 นอกเสียจากคุณจะอยู่ในปี 2014 หรือดีกว่า):

สามารถแก้ไขได้ด้วยบิลด์ต่อไปนี้:

  • 2005 SP3 CU 15 (> = 9.00.4325 และ <= 9.00.4999)
  • 2005 SP4 CU 2 (> = 9.00.5259)
  • 2008 SP1 CU 13 (> = 10.00.2816.00 และ <= 10.00.3999)
  • 2008 SP2 CU 3 (> = 10.00.4279.00 และ <= 10.00.5499)
  • ตามส่วนขยาย 2008 SP3 & SP4 (> = 10.00.5500)
  • 2008 R2 CU 7 (10.50.1777.0)
  • 2008 R2 SP1 CU 3 (> = 10.50.2769.0 AND <= 10.50.3999)
  • ตามส่วนขยาย 2008 R2 SP2 & SP3 (> = 10.50.4000)
  • ตามส่วนขยาย 2012, 2014, 2016 (> = 11.0)

(ครั้งต่อไปโปรดรวมผลลัพธ์ของSELECT @@VERSIONในคำถามของคุณ)

ฉันจะทราบว่าบทความ KB บอกว่า DATEDIFF สามารถประเมินจำนวนแถวต่ำเกินไปซึ่งตรงข้ามกับสิ่งที่เกิดขึ้นในสถานการณ์ของคุณ นั่นไม่ได้หมายความว่าการแก้ไขจะไม่มีผลกับคุณ ฉันคิดว่าถ้อยคำในบทความ KB ไม่ถูกต้องเนื่องจากการประมาณการสามารถไปได้ทั้งทางขึ้นอยู่กับข้อมูลและช่วงที่คุณกำลังดู

โพสต์บล็อกของฉันข้างต้นยืนยันว่าการแลกเปลี่ยนจะไม่เกิดขึ้นอีกในปี 2014 และต่อไป เพื่อความปลอดภัยฉันอาจจะทิ้งเศษ DATEDIFF จากภาคแสดงของคุณและใช้วิธีอื่นในการคำนวณจุดเริ่มต้นของช่วงของคุณ ฉันไม่แนะนำ overkill ของ 4199 หรือใช้ SQL แบบไดนามิกเพื่อป้องกันการแลกเปลี่ยนที่ไม่ดี


ขอบคุณสำหรับความช่วยเหลือ! ฉันลองคำแนะนำของคุณและเปลี่ยนแผนแล้ว นี่คือสิ่งที่เกิดขึ้นก่อนหน้านี้: s16.postimg.org/t5j6o1yed/fix_wrong.pngนี่คือวิธีที่มันเป็นหลังจากที่ฉันเปลี่ยนวันที่ของฉันโดยคุณ: postimg.org/image/5f725rj83 ฉันจะอ่าน URL ทั้งหมดที่คุณให้ฉัน . ไชโย
MrKudz
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.