ฟังก์ชั่นหน้าต่างทำให้เกิดแผนการดำเนินการที่น่ากลัวเมื่อถูกเรียกจากมุมมองที่มี parametrized ภายนอกโดยที่ 'clause


10

ฉันมีปัญหานี้มานานแล้วฉันพบวิธีแก้ปัญหาที่เหมาะกับฉันและลืมมันไป

แต่ตอนนี้มีคำถามนั้นดังนั้นฉันยินดีที่จะทำให้ปัญหานี้เกิดขึ้น

มีมุมมองที่รวมตารางบางอย่างในทางตรงไปตรงมามาก (คำสั่ง + คำสั่งซื้อ)

เมื่อถูกสอบถามโดยไม่มีwhereประโยคมุมมองจะส่งกลับหลายล้านบรรทัด
อย่างไรก็ตามไม่มีใครเคยเรียกมันว่าอย่างนั้น แบบสอบถามปกติคือ

select * from that_nasty_view where order_number = 123456;

สิ่งนี้จะส่งกลับประมาณ 10 ระเบียนจาก 5m

สิ่งสำคัญ: มุมมองมีฟังก์ชั่นหน้าต่างrank()ซึ่งแบ่งพาร์ติชันตามฟิลด์โดยใช้มุมมองที่ถูกสอบถามเสมอ:

rank() over (partition by order_number order by detail_line_number)

ตอนนี้ถ้ามุมมองนี้ถูกสอบถามด้วยพารามิเตอร์ที่แท้จริงในสตริงแบบสอบถามตรงตามที่แสดงข้างต้นก็จะส่งกลับแถวทันที แผนการดำเนินการเป็นเรื่องปกติ:

  • ดัชนีค้นหาทั้งสองตารางโดยใช้ดัชนีบนorder_number(ส่งคืน 10 แถว)
  • การคำนวณหน้าต่างเหนือผลลัพธ์เล็ก ๆ ที่ส่งคืน
  • การเลือก

อย่างไรก็ตามเมื่อมีการเรียกใช้มุมมองในแบบที่กำหนดสิ่งต่าง ๆ น่ารังเกียจ:

  • Index scanบนตารางทั้งหมดที่ละเว้นดัชนี ส่งคืนแถว 5 ม.
  • เข้าร่วมมาก
  • การคำนวณหน้าต่างทั้งหมดpartitions (ประมาณ 500k windows)
  • Filter เพื่อใช้ 10 แถวจาก 5m
  • เลือก

สิ่งนี้เกิดขึ้นในทุกกรณีเมื่อเกี่ยวข้องกับพารามิเตอร์ มันสามารถ SSMS:

declare @order_number int = 123456;
select * from that_nasty_view where order_number = @order_number;

มันสามารถเป็นไคลเอนต์ ODBC เช่น Excel:

select * from that_nasty_view where order_number = ?

หรืออาจเป็นไคลเอนต์อื่น ๆ ที่ใช้พารามิเตอร์และไม่ใช่การต่อข้อมูล sql

หากฟังก์ชั่นหน้าต่างถูกลบออกจากมุมมองมันจะทำงานได้อย่างรวดเร็วอย่างสมบูรณ์โดยไม่คำนึงว่าจะมีการสอบถามพารามิเตอร์หรือไม่

วิธีแก้ปัญหาของฉันคือการลบฟังก์ชั่นที่กระทำผิดและนำไปใช้ใหม่ในภายหลัง

แต่จะให้อะไร มันเป็นข้อบกพร่องอย่างแท้จริงในวิธีที่ SQL Server 2008 จัดการกับฟังก์ชั่นหน้าต่างหรือไม่?


order_number เป็นคีย์หลัก? ประเภทข้อมูลของคอลัมน์และพารามิเตอร์ตรงกันหรือไม่
gbn

order_numberไม่ใช่คีย์หลัก มันอยู่int not nullกับดัชนี nonclustered ในทั้งสองตาราง
GSerg

5
SQL Server 2005 มีปัญหากับเพรดิเคตดันในพื้นที่นี้ ฉันคิดว่าพวกเขาได้รับการแก้ไขแล้ว BTW ตัวอย่าง TSQL ของคุณใช้ตัวแปรไม่ใช่พารามิเตอร์ การเพิ่มOPTION (RECOMPILE)ความช่วยเหลือ?
Martin Smith

1
@ GSerg - ดังนั้นในแผนไม่ดีที่มีตัวกรองสุดท้ายมันมีประมาณ 5 ล้านแถวในตัวกรองและประมาณ 10 แถวออกมาตรงกับของจริง? ถ้าเป็นเช่นนั้นอาจเป็นปัญหาที่ผลักดันภาคยังคงไม่สมบูรณ์แล้ว
Martin Smith

คำตอบ:


5

สิ่งนี้ดูเหมือนจะเป็นปัญหาที่มีมายาวนานที่ทำให้การเปลี่ยนหน้าใหม่ในรูปแบบใดรูปแบบหนึ่งและยังคงมีอยู่ใน SQL Server 2012

บางกระทู้พูดถึงมัน

SQL Server เวอร์ชันปัจจุบันทั้งหมดจนถึงและรวมถึงปี 2012 ไม่สามารถกดตัวกรองบนกลุ่มการแบ่งพาร์ติชันที่ผ่านมาในโครงการลำดับสำหรับเพรดิเคตที่กำหนดพารามิเตอร์ยกเว้นถ้าoption(recompile)ใช้ (ถ้าใช้ 2008+)

อีกทางเลือกหนึ่งของrecompileคำใบ้คือการเขียนแบบสอบถามใหม่เพื่อใช้พารามิเตอร์แบบอินไลน์ TVF ตามที่แนะนำโดย @ a1ex07)


เพิ่งมีกรณีใน SQL Server 2014 เช่นกัน
Guillaume86

3

ฉันจะลองแทนที่มุมมองด้วย udf ที่มีค่าเป็นตาราง ด้วยวิธีนี้มันจะกรองระเบียนก่อนแล้วจึงใช้ฟังก์ชั่นหน้าต่าง ฟังก์ชั่นนี้อาจยอมรับพารามิเตอร์ตารางเพื่อให้คุณสามารถส่งผ่านหลายรายการorder_numberเข้าไปได้


วิธีแก้ปัญหาอื่นอีกใช่ ฉันทำอย่างนั้นไม่ได้เพราะลูกค้าไม่ทุกคนสามารถใช้ฟังก์ชันที่มีค่าเป็นตารางได้
GSerg

ทำไม? ฉันไม่แน่ใจ 100% แต่ฉันคิดว่าสิ่งที่คุณต้องมีก็คือเปลี่ยนการค้นหาเล็ก ๆ น้อย ๆ เป็นอย่างอื่นSELECT * FROM my_funct(12345)
a1ex07

หนึ่งในความต้องการก็คือแบบสอบถามจะสิ้นเปลืองโดยผู้ใช้ที่ใช้ Excel (นั่นคือโดย MS Query) และ MS Query จะไม่อนุญาตให้คุณทำเช่นนั้นอย่างน้อยก็ในรุ่นที่สูงถึง 2003
GSerg

it will filter records first, and then apply window functionไม่ถูกต้อง ไม่มีคำสั่งที่กำหนดให้ดำเนินการได้
Remus Rusanu
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.