SQL Server 2016 Bad Query Plan ล็อคฐานข้อมูลสัปดาห์ละครั้ง


16

สัปดาห์ละครั้งในช่วง 5 สัปดาห์ที่ผ่านมาในช่วงเวลาเดียวกันของวัน (เช้าตรู่อาจขึ้นอยู่กับกิจกรรมของผู้ใช้เมื่อผู้คนเริ่มใช้งาน), SQL Server 2016 (AWS RDS, มิร์เรอร์) เริ่มจับเวลาจำนวนมาก คำสั่ง

ปรับปรุงสถิติในตารางทั้งหมดแก้ไขได้ทันที

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

ครั้งล่าสุดที่ฉันเปิดใช้งาน Query Store เพื่อดูว่าฉันสามารถค้นหาแผนแบบสอบถาม / แบบสอบถามที่เฉพาะเจาะจงได้หรือไม่ ฉันคิดว่าฉันสามารถ จำกัด ให้แคบลงหนึ่ง:

แผนแบบสอบถามไม่ถูกต้อง

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

แผนแบบสอบถามที่ไม่ถูกต้องกำลังทำการสแกนดัชนี (บนตารางที่มีแถว 10k เท่านั้น) แผนคิวรีอื่น ๆ ที่ส่งคืนหน่วยเป็นมิลลิวินาทีใช้ในการสแกนแบบเดียวกัน แผนแบบสอบถามใหม่ล่าสุดหลังจากสร้างดัชนีใหม่จะค้นหาเท่านั้น แต่ถึงแม้จะไม่มีดัชนีนั้นก็ 99% ของเวลา แต่มันกลับมาภายในเวลาไม่กี่มิลลิวินาที แต่จากนั้นทุกสัปดาห์จะใช้เวลา> 40 วินาที

สิ่งนี้เริ่มเกิดขึ้นหลังจากย้ายไปยัง SQL Server 2016 จาก 2012

DBCC CHECKDB ส่งกลับไม่มีข้อผิดพลาด

  1. ดัชนีใหม่จะแก้ไขปัญหาทำให้ไม่เลือกแผนไม่ดีอีกครั้งหรือไม่
  2. ฉันควร "บังคับ" แผนที่ใช้ได้ดีหรือไม่?
  3. ฉันจะแน่ใจได้อย่างไรว่านี่จะไม่เกิดขึ้นกับแบบสอบถาม / แผนอื่น
  4. นี่เป็นอาการของปัญหาที่ใหญ่กว่าหรือไม่?

ดัชนีที่ฉันเพิ่งเพิ่ม:

CREATE NONCLUSTERED INDEX idx_AppointmetnAttendee_AttendeeType
ON [dbo].[AppointmentAttendee] ([UserID],[AttendeeType])

CREATE NONCLUSTERED INDEX [idx_appointment_start] ON [dbo].[Appointment]
(
    [ProjectID] ASC,
    [Start] ASC
)
INCLUDE (   [ID],
    [AllDay],
    [End],
    [Location],
    [Notes],
    [Title],
    [CreatedByID]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

ข้อความค้นหาแบบเต็ม:

https://pastebin.com/Z5szPBfu (สร้างโดย LINQ ฉันสามารถ / ควรสามารถปรับคอลัมน์ที่เลือกให้เหมาะสม แต่ควรไม่เกี่ยวข้องกับปัญหานี้)


ฉันเพิ่งสังเกตเห็นว่าการสแกนแผนก่อนหน้าซึ่งไม่ได้หมดเวลาอยู่บนโต๊ะที่แตกต่างกันขนาดใกล้เคียงกัน การนัดหมาย: 11931 แถว, การนัดหมายผู้เข้าร่วม: 11937 แถว
ชื่อการออกเสียงอย่างมืออาชีพ

คำตอบ:


16

ฉันจะตอบคำถามของคุณในลำดับที่แตกต่างจากที่คุณถาม

4. อาการนี้เป็นปัญหาใหญ่หรือไม่?

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

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

ฉันจะทิ้งตัวอย่างสถานการณ์ที่อาจนำไปสู่พฤติกรรมนี้ คุณพูดว่า:

ผู้ใช้บางคนสามารถมีบันทึกการอนุญาต 1 รายการบางรายการได้ถึง 20k

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

1. ดัชนีใหม่จะแก้ไขปัญหาทำให้ไม่เลือกแผนไม่ดีอีกครั้งหรือไม่

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

แผนแบบสอบถามไม่ดี

SQL Server ประมาณการว่ามีเพียงหนึ่งแถวจะถูกส่งกลับจากการเข้าร่วมในและ[Permission] สำหรับแต่ละแถวในการป้อนข้อมูลด้านนอกก็จะทำสแกนดัชนีคลัสเตอร์บน[Project] [Appointment]แถวทั้งหมดจะถูกสแกนจากตารางนี้ แต่เฉพาะแถวที่ตรงกับตัวกรองเท่านั้นที่[Start]จะถูกส่งกลับไปยังผู้ประกอบการเข้าร่วม ภายในตัวดำเนินการรวมผลลัพธ์จะลดลงอีก

แผนแบบสอบถามที่อธิบายข้างต้นอาจไม่เป็นไรหากมีเพียงหนึ่งแถวที่ส่งไปยังอินพุตภายนอกของการเข้าร่วม แต่ถ้าประมาณการ cardinality จากการเข้าร่วมเป็นสิ่งที่ผิดและเราได้รับการพูด, 1000 แถวแล้ว SQL Server 1000 [Appointment]จะทำสแกนดัชนีคลัสเตอร์บน ประสิทธิภาพของแผนแบบสอบถามมีความอ่อนไหวต่อปัญหาการประมาณค่ามาก

วิธีที่ตรงที่สุดที่จะไม่มีแผนแบบสอบถามนั้นอีกต่อไปคือการสร้างดัชนีครอบคลุมกับ[Appointment]ตาราง บางสิ่งบางอย่างเหมือนดัชนีบน[ProjectId]และ[Start]ควรทำ ดูเหมือนว่านี่เป็น[idx_appointment_start]ดัชนีที่คุณสร้างขึ้นเพื่อแก้ไขปัญหา วิธีที่จะกีดกันเซิร์ฟเวอร์ SQL จากการเลือกแผนการสอบถามก็คือการแก้ไขประมาณการ cardinality จากการเข้าร่วมในและ[Permission] [Project]วิธีทั่วไปในการทำเช่นนี้รวมถึงการเปลี่ยนรหัสการอัพเดตสถิติโดยใช้ CE ดั้งเดิมการสร้างสถิติหลายคอลัมน์ให้ข้อมูลเพิ่มเติมเกี่ยวกับตัวแปรโลคัล SQL Server เกี่ยวกับตัวแปรโลคัลเช่นด้วยRECOMPILEคำใบ้หรือการทำให้แถวเหล่านั้นเป็นตารางชั่วคราว เทคนิคเหล่านั้นส่วนใหญ่ไม่ได้เป็นวิธีที่ดีเมื่อคุณต้องการเวลาตอบสนองระดับ ms หรือต้องเขียนโค้ดผ่าน ORM

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

3. ฉันจะแน่ใจได้อย่างไรว่าสิ่งนี้จะไม่เกิดขึ้นกับแบบสอบถาม / แผนอื่น

ฉันเข้าใจว่าทำไมคุณถึงถามคำถามนี้ แต่มันเป็นคำถามที่กว้างมาก คำแนะนำเดียวของฉันคือพยายามเข้าใจสาเหตุที่แท้จริงของความไม่แน่นอนของแผนแบบสอบถามเพื่อตรวจสอบว่าคุณมีดัชนีที่เหมาะสมที่สร้างขึ้นสำหรับภาระงานของคุณและเพื่อทดสอบและตรวจสอบภาระงานของคุณอย่างรอบคอบ Microsoft มีคำแนะนำทั่วไปเกี่ยวกับวิธีจัดการกับการถดถอยของแผนแบบสอบถามที่เกิดจาก CE ตัวใหม่ใน SQL Server 2016:

เวิร์กโฟลว์ที่แนะนำสำหรับการอัพเกรดโปรเซสเซอร์แบบสอบถามเป็นรุ่นล่าสุดของรหัสคือ:

  1. อัปเกรดฐานข้อมูลเป็น SQL Server 2016 โดยไม่เปลี่ยนระดับความเข้ากันได้ของฐานข้อมูล (เก็บไว้ที่ระดับก่อนหน้า)

  2. เปิดใช้งานการจัดเก็บแบบสอบถามในฐานข้อมูล สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการเปิดใช้งานและการใช้ที่เก็บแบบสอบถามดูการตรวจสอบประสิทธิภาพโดยการใช้ Query Store

  3. รอเวลาเพียงพอในการรวบรวมข้อมูลตัวแทนของเวิร์กโหลด

  4. เปลี่ยนระดับความเข้ากันได้ของฐานข้อมูลเป็น 130

  5. การใช้ SQL Server Management Studio ประเมินว่ามีการถดถอยของประสิทธิภาพการทำงานกับแบบสอบถามเฉพาะหลังจากเปลี่ยนระดับความเข้ากันได้

  6. สำหรับกรณีที่มีการถดถอยบังคับแผนก่อนหน้าในที่เก็บแบบสอบถาม

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

ฉันไม่ได้บอกว่าคุณต้องลดระดับเป็น SQL Server 2012 และเริ่มใหม่ แต่เทคนิคทั่วไปที่อธิบายไว้อาจมีประโยชน์สำหรับคุณ

2. ฉันควร "บังคับ" แผนที่ใช้ได้ดีหรือไม่?

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.