INSERT แบบแถวเดียว…เลือกช้ากว่าการเลือกแบบแยก


18

รับตารางฮีปต่อไปนี้ด้วย 400 แถวหมายเลขตั้งแต่ 1 ถึง 400:

DROP TABLE IF EXISTS dbo.N;
GO
SELECT 
    SV.number
INTO dbo.N 
FROM master.dbo.spt_values AS SV
WHERE 
    SV.[type] = N'P'
    AND SV.number BETWEEN 1 AND 400;

และการตั้งค่าต่อไปนี้:

SET NOCOUNT ON;
SET STATISTICS IO, TIME OFF;
SET STATISTICS XML OFF;
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

ต่อไปนี้SELECTเสร็จสมบูรณ์คำสั่งในรอบ6 วินาที ( สาธิต , แผน ):

DECLARE @n integer = 400;

SELECT
    c = COUNT_BIG(*) 
FROM dbo.N AS N
CROSS JOIN dbo.N AS N2
CROSS JOIN dbo.N AS N3
WHERE 
    N.number <= @n
    AND N2.number <= @n
    AND N3.number <= @n
OPTION
    (OPTIMIZE FOR (@n = 1));

หมายเหตุ: @ OPTIMIZE FORข้อนี้เป็นเพียงการผลิตซ้ำขนาดที่สมเหตุสมผลที่รวบรวมรายละเอียดที่สำคัญของปัญหาที่แท้จริงรวมถึง cardinality misestimate ที่สามารถเกิดขึ้นได้ด้วยเหตุผลหลายประการ

เมื่อเอาต์พุตแถวเดียวถูกเขียนลงในตารางจะใช้เวลา19 วินาที ( สาธิต , วางแผน ):

DECLARE @T table (c bigint NOT NULL);

DECLARE @n integer = 400;

INSERT @T
    (c)
SELECT
    c = COUNT_BIG(*) 
FROM dbo.N AS N
CROSS JOIN dbo.N AS N2
CROSS JOIN dbo.N AS N3
WHERE 
    N.number <= @n
    AND N2.number <= @n
    AND N3.number <= @n
OPTION
    (OPTIMIZE FOR (@n = 1));

แผนการดำเนินการปรากฏเหมือนกันนอกเหนือจากการแทรกของหนึ่งแถว

ดูเหมือนว่าเวลาพิเศษทั้งหมดจะถูกใช้โดยการใช้งาน CPU

เหตุใดINSERTคำสั่งจึงช้าลงมาก

คำตอบ:


21

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

การใช้คำผิดอย่างผิด ๆ โดยเจตนาOPTIMIZE FORหมายถึงการสแกนจำนวนมากเกินกว่าที่โปรแกรมเพิ่มประสิทธิภาพคาดไว้และจะไม่แนะนำสปูลตามปกติ

การรวมกันของปัจจัยนี้หมายความว่าประสิทธิภาพมีความอ่อนไหวต่อจำนวนล็อคที่ต้องใช้ในขณะทำงาน

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

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

จำนวนกิจกรรมการล็อคบัญชีมหาศาลสำหรับซีพียูพิเศษและเวลาที่ผ่านไป

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

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

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

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

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