แผนปฏิบัติการช้าสำหรับ Proc ที่เก็บไว้


15

ฉันกำลังพยายามที่จะเข้าใจปัญหาที่เรามีกับ SQL Server 2000 เราเป็นเว็บไซต์ที่ทำธุรกรรมปานกลางและเรามี proc ที่เก็บไว้sp_GetCurrentTransactionsซึ่งเรียกว่ารับรหัสลูกค้าและสองวัน

ตอนนี้ขึ้นอยู่กับวันที่และลูกค้าแบบสอบถามนี้สามารถส่งคืนอะไรก็ได้จากศูนย์ถึง 1,000 แถว

ปัญหา: สิ่งที่เราพบคือทันใดนั้นเราจะได้รับข้อผิดพลาดจำนวนมาก (โดยทั่วไปExecution Timeout Expiredหรือคล้ายกัน) สำหรับลูกค้าเฉพาะขณะที่พวกเขาลองดำเนินการ proc ที่เก็บไว้ ดังนั้นเราตรวจสอบแบบสอบถามเรียกใช้ใน SSMS และพบว่าใช้เวลา 30 วินาที ดังนั้นเราจึงคอมไพล์ proc ที่เก็บไว้และ -bang- อีกครั้งมันทำงานใน 300ms

ฉันได้พูดคุยกับ DBA ของเราเกี่ยวกับเรื่องนี้แล้ว เขาบอกฉันว่าฐานข้อมูลสร้างแผนแบบสอบถามเมื่อเราสร้าง proc ที่เก็บไว้ เขาบอกว่ามันเป็นแผนการที่ดีสำหรับชุดของพารามิเตอร์นั้น แต่ถ้าคุณโยนชุดของพารามิเตอร์ที่กำหนดไว้แผนจะไม่เป็นแผนการที่ดีที่สุดสำหรับข้อมูลนั้นและคุณจะเห็นว่ามันทำงานช้า

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

มันให้ความรู้สึกเหมือนย้อนกลับไปหาฉันและฉันรู้สึกว่าต้องมีวิธีแก้ไข มีวิธีอื่นในการจัดการกับปัญหานี้หรือไม่?

คำตอบใด ๆ และทั้งหมดได้รับการชื่นชม


มีคำสั่ง if / else ใน proc หรือไม่ ฉันเคยเห็นสิ่งนี้เกิดขึ้นเมื่อแผนถูกแคชในคำสั่ง if แล้วพยายามดำเนินการภายใต้บล็อกอื่นโดยใช้แผนผิด ข้อผิดพลาดเหล่านี้สอดคล้องกับการเปลี่ยนแปลงใน proc หรือไม่?
Jeremy Gray

@Jeremy: ไม่มีการเปลี่ยนแปลง proc และไม่มีคำสั่งอื่น / if
Ciaran Archer

คำตอบ:


14

ปัญหานี้เรียกว่าพารามิเตอร์การดมกลิ่น

SQL Server รุ่นที่ใหม่กว่าให้ตัวเลือกเพิ่มเติมแก่คุณในการจัดการกับมันเช่นOPTION (RECOMPILE)หรือOPTIMIZE FORคำแนะนำ

คุณอาจลองประกาศตัวแปรในโพรซีเดอร์ที่เก็บไว้, การกำหนดค่าพารามิเตอร์ให้กับตัวแปรและใช้ตัวแปรแทนพารามิเตอร์ตามที่ฟังดูเหมือนว่าส่วนใหญ่เวลาที่คุณได้รับแผนที่น่าพอใจพอสมควร

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

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

ข้อเสียคือเวลารันของการประมวลผลบางครั้งอาจมากกว่าแผนการที่ปรับให้เหมาะกับค่าพารามิเตอร์เหล่านั้นโดยเฉพาะดังนั้นจึงเป็นการแลกเปลี่ยนเวลารวบรวมเทียบกับเวลาดำเนินการ


3
หรือ "ผูก peeking" ในคำศัพท์ Oracle
Gaius

ขอบคุณ @Gaius, ดีที่จะรู้คำศัพท์มากกว่าหนึ่ง RDBMS;)
อังเดรRînea

6

แทนที่จะใช้ไดนามิก SQL คุณสามารถเปลี่ยนการเรียก proc เป็น:

EXEC Database.dbo.usp_Myprocedure 'Parameter' WITH RECOMPILE

WITH RECOMPILEกองกำลัง (คุณ guessed มัน!) recompile ของการวางแผนการดำเนินการเมื่อใดก็ตามที่มีการเรียกใช้

คุณสามารถรวมWITH RECOMPILEไว้ในคำจำกัดความของ proc ที่เก็บไว้:

CREATE PROCEDURE usp.MyProcedure (Parameters)
WITH RECOMPILE
AS
...

2

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

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

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

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


1

คุณสามารถลองSET FORCEPLANและสร้างดัชนีคำแนะนำ

http://msdn.microsoft.com/en-us/library/ms188344.aspx
โดยพื้นฐานแล้วจะช่วยให้คุณสามารถเลือกสิ่งที่จะเข้าร่วมได้

คุณสามารถมีคำใบ้ดัชนีเพื่อให้แน่ใจว่าเซิร์ฟเวอร์ SQL ใช้ดัชนีที่ถูกต้อง


0

อืม ... ถ้าเราให้ความสำคัญกับขั้นตอนการจัดเก็บนี้ฉันจะประหลาดใจที่ใช้แผนการดำเนินการแคชจะทำให้เกิดปัญหาที่คุณเห็น ฉันจะขอดูแผนการดำเนินการของกระบวนงานที่เก็บไว้โดยใช้ชุดพารามิเตอร์สำหรับลูกค้าและวันที่สองวัน ฉันสงสัยว่าดัชนีที่เฉพาะเจาะจงยิ่งขึ้นจะมีประโยชน์ -> เช่นใน customerId และสองวันเท่านั้นหรือไม่


2
ทำไมต้องประหลาดใจ การดมกลิ่นพารามิเตอร์เป็นปัญหาที่พบได้บ่อยในอาการเหล่านี้และดูเหมือนว่า DBA ได้ระบุว่าเป็นปัญหา
Martin Smith

@MartinSmith - ฉันแปลกใจนิดหน่อยที่ DBA ที่รู้เรื่องการดมกลิ่นผู้รอบรู้ไม่รู้เกี่ยวกับคำแนะนำการคอมไพล์ซ้ำอีกครั้ง ...
JNK

@JNK - จริง ไม่แน่ใจว่าทำไมพวกเขาถึงไม่พูดถึงสิ่งนั้น
Martin Smith

0

ประสิทธิภาพที่ลดลงอย่างกะทันหันดูเหมือนแผนการสอบถามที่ไม่มีประสิทธิภาพที่อาจเกิดจากสถิติที่ขาดหายไป เรียกใช้ตัวสร้างโปรไฟล์ SQL Server ด้วยหมวดหมู่เหตุการณ์ "ข้อผิดพลาดและคำเตือน" และดูว่ามีคำเตือนเกี่ยวกับสถิติที่หายไปหรือไม่

คุณอาจขาดดัชนีหรือคุณอาจจำเป็นต้องจัดเรียงดัชนีเนื่องจากอาจมีการแยกส่วนเกินกว่าที่ SQL Server จะใช้ทำให้คิดว่าการสแกนตารางจะทำให้ I / O น้อยลง

@JNK ยกประเด็นที่ยอดเยี่ยมเกี่ยวกับ procs ที่เก็บไว้ - สิ่งเหล่านี้ได้รับการรวบรวมล่วงหน้าและแผนแบบสอบถามจะถูกเก็บไว้พร้อมกับขั้นตอนการจัดเก็บ

ฉันไม่เห็นด้วยกับการใช้กับ RECOMPILEเนื่องจากคุณสูญเสียผลประโยชน์จากแผนแบบสอบถามที่จัดเก็บและนำกลับมาใช้ใหม่ มีบางกรณีที่มีความจำเป็น - เช่นหากสถิติการกระจายของคุณในตารางพื้นฐานแตกต่างกันมากระหว่างการโทร แต่โดยทั่วไปเมื่อข้อมูลในตารางครบกำหนดแล้วการกระจายข้อมูลภายในตารางจะแตกต่างกันเล็กน้อย

ดังนั้นเพื่อสรุป:

  1. ตรวจสอบสถิติที่หายไป
  2. ตรวจสอบดัชนีการแตกแฟรกเมนต์
  3. สร้างและใช้ proc ที่เก็บไว้
  4. โปรดเปลี่ยนชื่อ proc - sp_ เป็นเนมสเปซคำนำที่สงวนไว้อย่างนุ่มนวลสำหรับระบบภายใน procs ของเซิร์ฟเวอร์ SQL ส่งผลให้ SQL Server ค้นหาในฐานข้อมูลหลักสำหรับกระบวนการที่เก็บไว้เหล่านั้นเสมอ การเปลี่ยนชื่อ proc usp_ แทน sp_ จะทำให้ประสิทธิภาพเพิ่มขึ้น แต่ฉันสงสัยว่าปัญหาของคุณในกรณีนี้
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.