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


34

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

แบบสอบถามเพื่อสร้างตารางทดสอบและกรอกข้อมูลคือ:

CREATE TABLE [dbo].[IndexTestTable](
    [id] [int] IDENTITY(1,1) PRIMARY KEY,
    [Name] [nvarchar](20) NULL,
    [val1] [bigint] NULL,
    [val2] [bigint] NULL)

DECLARE @counter INT;
SET @counter = 1;

WHILE @counter < 500000
BEGIN
    INSERT INTO IndexTestTable
      (
        -- id -- this column value is auto-generated
        NAME,
        val1,
        val2
      )
    VALUES
      (
        'Name' + CAST((@counter % 100) AS NVARCHAR),
        RAND() * 10000,
        RAND() * 20000
      );

    SET @counter = @counter + 1;
END

-- Index in question
CREATE NONCLUSTERED INDEX [IndexA] ON [dbo].[IndexTestTable]
(
    [Name] ASC
)
INCLUDE (   [id],
    [val1],
    [val2])

ตอนนี้แบบสอบถาม 1 ซึ่งได้รับการปรับปรุง (เพียงเล็กน้อยเท่านั้น แต่การปรับปรุงมีความสอดคล้องกัน) คือ:

SELECT *
FROM   IndexTestTable I1
       JOIN IndexTestTable I2
            ON  I1.ID = I2.ID
WHERE  I1.Name = 'Name1'

สถิติและแผนการดำเนินการโดยไม่มีดัชนี (ในกรณีนี้ตารางจะใช้ดัชนีคลัสเตอร์เริ่มต้น):

(5000 row(s) affected)
Table 'IndexTestTable'. Scan count 2, logical reads 5580, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(1 row(s) affected)

 SQL Server Execution Times:
   CPU time = 109 ms,  elapsed time = 294 ms.

ป้อนคำอธิบายรูปภาพที่นี่

ขณะนี้เปิดใช้งานดัชนีแล้ว:

(5000 row(s) affected)
Table 'IndexTestTable'. Scan count 2, logical reads 2819, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(1 row(s) affected)

 SQL Server Execution Times:
   CPU time = 94 ms,  elapsed time = 231 ms.

ป้อนคำอธิบายรูปภาพที่นี่

ตอนนี้เคียวรีที่ช้าลงเนื่องจากดัชนี (เคียวรีนั้นไม่มีความหมายเนื่องจากถูกสร้างขึ้นสำหรับการทดสอบเท่านั้น):

SELECT I1.Name,
       SUM(I1.val1),
       SUM(I1.val2),
       MIN(I2.Name),
       SUM(I2.val1),
       SUM(I2.val2)
FROM   IndexTestTable I1
       JOIN IndexTestTable I2
            ON  I1.Name = I2.Name
WHERE   
       I2.Name = 'Name1'
GROUP BY
       I1.Name

ด้วยการเปิดใช้งานดัชนีคลัสเตอร์:

(1 row(s) affected)
Table 'IndexTestTable'. Scan count 4, logical reads 60, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 1, logical reads 155106, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(1 row(s) affected)

 SQL Server Execution Times:
   CPU time = 17207 ms,  elapsed time = 17337 ms.

ป้อนคำอธิบายรูปภาพที่นี่

ขณะนี้มีการปิดใช้งานดัชนี:

(1 row(s) affected)
Table 'IndexTestTable'. Scan count 5, logical reads 8642, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 2, logical reads 165212, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(1 row(s) affected)

 SQL Server Execution Times:
   CPU time = 17691 ms,  elapsed time = 9073 ms.

ป้อนคำอธิบายรูปภาพที่นี่

คำถามคือ:

  1. แม้ว่า SQL Server จะแนะนำดัชนี แต่ทำไมมันถึงทำให้ช้าลงด้วยความแตกต่างที่สำคัญ?
  2. การเข้าร่วม Nested Loop คืออะไรซึ่งใช้เวลาส่วนใหญ่และวิธีการปรับปรุงเวลาดำเนินการ
  3. มีบางอย่างที่ฉันทำผิดหรือพลาด?
  4. ด้วยดัชนีเริ่มต้น (บนคีย์หลักเท่านั้น) เหตุใดจึงใช้เวลาน้อยลงและมีดัชนีที่ไม่เป็นคลัสเตอร์สำหรับแต่ละแถวในตารางการเข้าร่วมแถวของตารางที่เข้าร่วมควรจะพบได้เร็วขึ้นเนื่องจากการเข้าร่วมอยู่ในคอลัมน์ชื่อที่ สร้างดัชนีแล้ว สิ่งนี้สะท้อนให้เห็นในแผนการดำเนินการแบบสอบถามและค่าดัชนีค้นหาน้อยกว่าเมื่อดัชนีใช้งานอยู่ แต่ทำไมยังช้ากว่า อะไรคือสิ่งที่อยู่ใน Nested Loop ด้านนอกซ้ายเข้าร่วมที่ทำให้เกิดการชะลอตัว?

ใช้ SQL Server 2012

คำตอบ:


23

แม้ว่า SQL Server จะแนะนำดัชนี แต่ทำไมมันถึงทำให้ช้าลงด้วยความแตกต่างที่สำคัญ?

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

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

การเข้าร่วม Nested Loop คืออะไรซึ่งใช้เวลาส่วนใหญ่และวิธีการปรับปรุงเวลาดำเนินการ

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

มีบางอย่างที่ฉันทำผิดหรือพลาด?

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

สแกนแผน

ในแผนการใช้การค้นหาดัชนีแบบไม่รวมกลุ่มงานจะสิ้นสุดลงโดยดำเนินการทั้งหมดโดยหนึ่งเธรด:

แสวงหาแผน

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

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

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

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

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

SELECT
    val1,
    val2
INTO #Temp
FROM dbo.IndexTestTable AS ITT
WHERE Name = N'Name1';

SELECT 
    N'Name1',
    SUM(T.val1),
    SUM(T.val2),
    MIN(I2.Name),
    SUM(I2.val1),
    SUM(I2.val2)
FROM   #Temp AS T
CROSS JOIN IndexTestTable I2
WHERE
    I2.Name = 'Name1'
OPTION (FORCE ORDER, QUERYTRACEON 8690);

DROP TABLE #Temp;

สิ่งนี้ส่งผลให้เกิดแผนการที่ใช้การค้นหาดัชนีที่มีประสิทธิภาพมากขึ้นไม่มีฟีเจอร์สปูลโต๊ะและกระจายการทำงานข้ามเธรดได้เป็นอย่างดี:

แผนที่เหมาะสม

ในระบบของฉันแผนนี้ดำเนินการเร็วกว่ารุ่นสแกนดัชนีอย่างมาก

หากคุณสนใจในการเรียนรู้เพิ่มเติมเกี่ยวกับ internals ของการดำเนินการค้นหาขนานคุณอาจต้องการที่จะดู PASS ประชุมสุดยอดบันทึก


0

ไม่ใช่คำถามของดัชนี แต่เป็นคำถามที่เขียนไม่ดี คุณมีชื่อที่ไม่ซ้ำกัน 100 ค่าซึ่งจะทำให้มีจำนวนเฉพาะ 5000 ต่อชื่อ

ดังนั้นสำหรับแต่ละบรรทัดในตารางที่ 1 คุณกำลังรวม 5,000 จากตารางที่ 2 คุณสามารถพูดได้ 25020004 บรรทัด

ลองสิ่งนี้โปรดทราบว่านี่เป็นเพียงดัชนีเดียวเท่านั้นซึ่งเป็นดัชนีที่คุณอยู่ในรายการ

    DECLARE @Distincts INT
    SET @Distincts = (SELECT  TOP 1 COUNT(*) FROM IndexTestTable I1 WHERE I1.Name = 'Name1' GROUP BY I1.Name)
    SELECT I1.Name
    , @Distincts
    , SUM(I1.val1) * @Distincts
    , SUM(I1.val2) * @Distincts
    , MIN(I2.Name)
    , SUM(I2.val1)
    , SUM(I2.val2)
    FROM   IndexTestTable I1
    LEFT OUTER JOIN

    (
        SELECT I2.Name
        , SUM(I2.val1) val1
        , SUM(I2.val2) val2
        FROM IndexTestTable I2
        GROUP BY I2.Name
    ) I2 ON  I1.Name = I2.Name
    WHERE I1.Name = 'Name1'
    GROUP BY  I1.Name

และเวลา:

    SQL Server parse and compile time: 
       CPU time = 0 ms, elapsed time = 8 ms.
    Table 'IndexTestTable'. Scan count 1, logical reads 31, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

     SQL Server Execution Times:
       CPU time = 0 ms,  elapsed time = 1 ms.

    (1 row(s) affected)
    Table 'IndexTestTable'. Scan count 2, logical reads 62, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

     SQL Server Execution Times:
       CPU time = 16 ms,  elapsed time = 10 ms.

ป้อนคำอธิบายรูปภาพที่นี่

คุณไม่สามารถตำหนิดัชนี SQL สำหรับแบบสอบถามที่เกิดขึ้นไม่ดี


1
ขอบคุณสำหรับคำตอบและใช่แบบสอบถามสามารถปรับปรุงได้ แต่ตรรกะของคำถามของฉันคือการที่มีดัชนีเริ่มต้น (บนคีย์หลักเท่านั้น) ทำไมมันใช้เวลาน้อยลงและมีดัชนีที่ไม่ใช่คลัสเตอร์สำหรับแต่ละแถวใน ตารางการเข้าร่วมแถวของตารางที่เข้าร่วมควรจะพบได้เร็วขึ้นซึ่งสะท้อนให้เห็นในแผนการดำเนินการแบบสอบถามและค่าใช้จ่ายดัชนีค้นหาน้อยกว่าเมื่อดัชนีใช้งานอยู่ แต่ทำไมยังช้ากว่า อะไรคือสิ่งที่อยู่ใน Nested Loop ด้านนอกซ้ายเข้าร่วมที่ทำให้เกิดการชะลอตัว? ฉันได้แก้ไขคำถามเพื่อเพิ่มความคิดเห็นนี้เพื่อทำให้คำถามชัดเจนยิ่งขึ้น
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.