เอาชนะการผสานเข้าร่วม (สแกนดัชนี) ด้วยค่าคีย์เดี่ยวอย่างชัดเจนบนคีย์ต่างประเทศ


9

เพิ่ม 7/11ปัญหานี้เกิดจากการหยุดชะงักเนื่องจากการสแกนดัชนีระหว่าง MERGE JOIN ในกรณีนี้ธุรกรรมที่พยายามรับ S lock ในดัชนีทั้งหมดที่ตารางหลัก FK แต่ก่อนหน้านี้ธุรกรรมอื่นวาง X lock ไว้ในค่าคีย์ของดัชนี

ให้ฉันเริ่มต้นด้วยตัวอย่างเล็ก ๆ (ใช้ TSQL2012 DB จาก 70-461 cource):

CREATE TABLE [Sales].[Orders](
[orderid] [int] IDENTITY(1,1) NOT NULL,
[custid] [int] NULL,
[empid] [int] NOT NULL,
[shipperid] [int] NOT NULL,
... )

คอลัมน์[custid], [empid], [shipperid]เป็นพารามิเตอร์ที่มีการเชื่อมโยงกัน[Sales].[Customers], [HR].[Employees], [Sales].[Shippers]ตามลำดับ ในแต่ละกรณีเรามีดัชนีคลัสเตอร์ในคอลัมน์ที่อ้างถึงในตาราง parrent

ALTER TABLE [Sales].[Orders]  WITH CHECK ADD  CONSTRAINT [FK_Orders_Customers] FOREIGN KEY([custid]) REFERENCES [Sales].[Customers] ([custid])
ALTER TABLE [Sales].[Orders]  WITH CHECK ADD  CONSTRAINT [FK_Orders_Employees] FOREIGN KEY([empid]) REFERENCES [HR].[Employees] ([empid])
ALTER TABLE [Sales].[Orders]  WITH CHECK ADD  CONSTRAINT [FK_Orders_Shippers] FOREIGN KEY([shipperid])REFERENCES [Sales].[Shippers] ([shipperid])

ฉันกำลังพยายามไปINSERT [Sales].[Orders] SELECT ... FROMยังตารางอื่นที่เรียกว่า[Sales].[OrdersCache]ซึ่งมีโครงสร้างเหมือนกับ[Sales].[Orders]คีย์ต่างประเทศยกเว้น สิ่งสำคัญอีกอย่างที่อาจกล่าวถึงในตาราง[Sales].[OrdersCache]คือดัชนีแบบคลัสเตอร์

CREATE CLUSTERED INDEX idx_c_OrdersCache ON Sales.OrdersCache ( custid, empid )

ตามที่คาดไว้เมื่อฉันพยายามแทรกข้อมูลปริมาณน้อย LOOP JOIN ทำงานได้ดีทำให้ดัชนีค้นหาคีย์ต่างประเทศ

ด้วยข้อมูลจำนวนมาก MERGE JOIN ถูกใช้โดยเครื่องมือเพิ่มประสิทธิภาพการสืบค้นเป็นวิธีที่มีประสิทธิภาพมากที่สุดในการรักษาคีย์ foregn ในแบบสอบถาม

และไม่มีอะไรเกี่ยวข้องกับมันยกเว้นการใช้ OPTION (LOOP JOIN) ในกรณีของเราด้วยปุ่มต่างประเทศหรือ INP LOOP JOIN ในกรณี JOIN อย่างชัดเจน

ด้านล่างนี้เป็นคำถามที่ฉันพยายามเรียกใช้ในสภาพแวดล้อมของฉัน:

INSERT Sales.Orders (
        custid, empid, shipperid, ... )
SELECT  custid, empid, 2, ...
FROM Sales.OrdersCache

เมื่อดูที่แผนเราจะเห็นว่ากุญแจทั้งสามที่ผ่านการตรวจสอบความถูกต้องกับ MERGE JOIN ไม่ใช่วิธีที่เหมาะสมสำหรับฉันเนื่องจากใช้ดัชนี INDEX พร้อมการล็อคดัชนีทั้งหมด ผสานเข้าร่วมในระหว่างการตรวจสอบคีย์ต่างประเทศ

การใช้ OPTION (LOOP JOIN) ไม่เหมาะสมเนื่องจากมีค่าใช้จ่ายมากกว่าการรวม MERGE เกือบ 15% (ฉันคิดว่าการถดถอยจะยิ่งใหญ่ขึ้นเมื่อปริมาณข้อมูลเพิ่มขึ้น)

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

  • ทำให้ LOOP JOIN, MERGE JOIN, HASH JOIN ถ้าเรามีเซตย่อยที่ไม่ได้กำหนดไว้สำหรับการตรวจสอบ JOIN
  • หากมีเพียงค่าเดียวที่ชัดเจนของคอลัมน์ที่ตรวจสอบแล้วเราจะทำการตรวจสอบเพียงครั้งเดียว (INDEX SEEK)

มีรูปแบบทั่วไปที่จะข้ามสถานการณ์ข้างต้นโดยใช้โครงสร้างรหัสวัตถุ DDL เพิ่มเติมและอื่น ๆ ?

เพิ่ม 20/07 สารละลาย. เครื่องมือเพิ่มประสิทธิภาพการค้นหาได้ทำการเพิ่มประสิทธิภาพการตรวจสอบความถูกต้องของ 'คีย์เดียว - คีย์ต่างประเทศ' โดยใช้ MERGE JOIN และสร้างเฉพาะสำหรับฝ่ายขายตารางผู้ส่งสินค้าออกจาก LOOP JOIN สำหรับการรวมอื่นในการสืบค้นในเวลาเดียวกัน เนื่องจากฉันมีไม่กี่แถวในตารางหลักของเครื่องมือค้นหาข้อความใช้อัลกอริธึมการรวม Sort-merge และเปรียบเทียบแต่ละแถวในตารางภายในกับตารางหลักเพียงครั้งเดียว ดังนั้นนั่นคือคำตอบสำหรับคำถามของฉันหากมีกลไกเฉพาะใด ๆ ในการประมวลผลค่าเดียวในชุดในระหว่างการตรวจสอบความถูกต้องของคีย์เดียว นั่นไม่ใช่การตัดสินใจที่สมบูรณ์แบบ แต่นั่นคือวิธีที่ SQL Server ปรับเคสให้เหมาะสม

ผลกระทบต่อการสืบสวนพบว่าในกรณีของฉันคำสั่ง MERGE JOIN และ LOOP JOIN แทรกเท่ากับประมาณ 750 แถวที่แทรกพร้อมกันพร้อมกับความเหนือกว่าของ MERGE JOIN (ในทรัพยากรเวลา CPU) ดังนั้นการใช้ OPTION (LOOP JOIN) จึงเป็นทางออกที่เหมาะสมสำหรับกระบวนการทางธุรกิจของฉัน

คำตอบ:


8

การใช้ OPTION (LOOP JOIN) ไม่เหมาะสมเนื่องจากมีค่าใช้จ่ายมากกว่าการรวม MERGE เกือบ 15%

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

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

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

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

มีรูปแบบทั่วไปที่จะข้ามสถานการณ์ข้างต้นโดยใช้โครงสร้างรหัสวัตถุ DDL เพิ่มเติมและอื่น ๆ ?

ไม่ว่าฉันรู้ ความเสี่ยงจากการหยุดชะงักของการรวมกับการรวมการตรวจสอบความถูกต้องของคีย์ต่างประเทศเป็นที่รู้จักกันดีโดยมีวิธีแก้ปัญหาที่ใช้กันอย่างแพร่หลายเป็นOPTION (LOOP JOIN)คำใบ้ ไม่มีวิธีที่จะหลีกเลี่ยงการล็อกที่ใช้ร่วมกันระหว่างการตรวจสอบคีย์ต่างประเทศเนื่องจากสิ่งเหล่านี้จำเป็นสำหรับความถูกต้องแม้ภายใต้ระดับการแยกเวอร์ชันแถว

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

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