Chỉ mục không thực hiện nhanh hơn và trong một số trường hợp làm chậm truy vấn. Tại sao nó như vậy?


34

Tôi đã thử nghiệm với các chỉ mục để tăng tốc mọi thứ, nhưng trong trường hợp tham gia, chỉ mục không cải thiện thời gian thực hiện truy vấn và trong một số trường hợp, nó đang làm mọi thứ chậm lại.

Truy vấn để tạo bảng thử nghiệm và điền vào nó với dữ liệu là:

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])

Bây giờ truy vấn 1, được cải thiện (chỉ một chút nhưng sự cải thiện là phù hợp) là:

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

Số liệu thống kê và kế hoạch thực hiện không có Index (trong trường hợp này là bảng sử dụng chỉ mục được nhóm mặc định):

(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.

nhập mô tả hình ảnh ở đây

Bây giờ với Index được bật:

(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.

nhập mô tả hình ảnh ở đây

Bây giờ truy vấn chậm lại do chỉ mục (truy vấn là vô nghĩa vì nó chỉ được tạo để thử nghiệm):

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

Với chỉ số cụm được kích hoạt:

(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.

nhập mô tả hình ảnh ở đây

Bây giờ với Index bị vô hiệu hóa:

(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.

nhập mô tả hình ảnh ở đây

Các câu hỏi là:

  1. Mặc dù chỉ mục được đề xuất bởi SQL Server, tại sao nó làm mọi thứ chậm lại bởi một sự khác biệt đáng kể?
  2. Tham gia Nested Loop đang chiếm phần lớn thời gian và làm thế nào để cải thiện thời gian thực hiện của nó?
  3. Có điều gì đó mà tôi đang làm sai hoặc đã bỏ lỡ?
  4. Với chỉ mục mặc định (chỉ trên khóa chính), tại sao lại mất ít thời gian hơn và với chỉ mục không được nhóm hiện diện, đối với mỗi hàng trong bảng tham gia, hàng bảng tham gia sẽ được tìm thấy nhanh hơn, bởi vì tham gia nằm trên cột Tên trên đó chỉ số đã được tạo. Điều này được phản ánh trong kế hoạch thực hiện truy vấn và chi phí Tìm kiếm Index sẽ ít hơn khi IndexA hoạt động, nhưng tại sao vẫn chậm hơn? Ngoài ra những gì trong Nested Loop bên ngoài tham gia bên ngoài đang gây ra sự chậm lại?

Sử dụng SQL Server 2012

Câu trả lời:


23

Mặc dù chỉ mục được đề xuất bởi SQL Server, tại sao nó làm mọi thứ chậm lại bởi một sự khác biệt đáng kể?

Đề xuất chỉ mục được thực hiện bởi trình tối ưu hóa truy vấn. Nếu nó đi qua một lựa chọn hợp lý từ một bảng không được phục vụ tốt bởi một chỉ mục hiện có, nó có thể thêm một đề xuất "chỉ mục bị thiếu" vào đầu ra của nó. Những đề xuất này là cơ hội; chúng không dựa trên phân tích đầy đủ của truy vấn và không tính đến các cân nhắc rộng hơn. Tốt nhất, chúng là một dấu hiệu cho thấy có thể lập chỉ mục hữu ích hơn, và một DBA có kỹ năng nên xem xét.

Một điều khác để nói về các đề xuất chỉ mục bị thiếu là chúng dựa trên mô hình chi phí của trình tối ưu hóa và trình tối ưu hóa ước tính bằng cách chỉ số được đề xuất có thể giảm chi phí ước tính của truy vấn. Các từ khóa ở đây là "mô hình" và "ước tính". Trình tối ưu hóa truy vấn biết rất ít về cấu hình phần cứng của bạn hoặc các tùy chọn cấu hình hệ thống khác - mô hình của nó chủ yếu dựa trên các số cố định xảy ra để tạo ra kết quả kế hoạch hợp lý cho hầu hết mọi người trên hầu hết thời gian. Ngoài các vấn đề với số chi phí chính xác được sử dụng, kết quả luôn là ước tính - và ước tính có thể sai.

Tham gia Nested Loop đang chiếm phần lớn thời gian và làm thế nào để cải thiện thời gian thực hiện của nó?

Có rất ít việc phải làm để cải thiện hiệu suất của chính hoạt động tham gia chéo; các vòng lặp lồng nhau là cách thực hiện vật lý duy nhất có thể cho phép nối chéo. Bộ đệm bảng ở phía bên trong của phép nối là một tối ưu hóa để tránh quét lại mặt trong cho mỗi hàng bên ngoài. Việc đây có phải là một tối ưu hóa hiệu suất hữu ích hay không phụ thuộc vào nhiều yếu tố khác nhau, nhưng trong các thử nghiệm của tôi, truy vấn sẽ tốt hơn nếu không có nó. Một lần nữa, đây là hậu quả của việc sử dụng mô hình chi phí - CPU và hệ thống bộ nhớ của tôi có thể có các đặc tính hiệu suất khác với bạn. Không có gợi ý truy vấn cụ thể để tránh bộ đệm bảng, nhưng có một cờ theo dõi không có giấy tờ (8690) mà bạn có thể sử dụng để kiểm tra hiệu năng thực thi có và không có bộ đệm. Nếu đây là một vấn đề hệ thống sản xuất thực sự, kế hoạch không có ống chỉ có thể bị buộc sử dụng hướng dẫn kế hoạch dựa trên kế hoạch được tạo với TF 8690 được bật. Không nên sử dụng cờ theo dõi không có giấy tờ trong sản xuất vì việc cài đặt trở nên không được hỗ trợ về mặt kỹ thuật và cờ theo dõi có thể có tác dụng phụ không mong muốn.

Có điều gì đó mà tôi đang làm sai hoặc đã bỏ lỡ?

Điều chính bạn đang thiếu là mặc dù kế hoạch sử dụng chỉ mục không bao gồm có chi phí ước tính thấp hơn theo mô hình của trình tối ưu hóa, nhưng nó có một vấn đề đáng kể về thời gian thực hiện. Nếu bạn xem phân phối các hàng trên các luồng trong kế hoạch bằng cách sử dụng Chỉ mục cụm, bạn có thể sẽ thấy phân phối hợp lý tốt:

Kế hoạch quét

Trong kế hoạch sử dụng Tìm kiếm chỉ mục không độc quyền, công việc cuối cùng được thực hiện hoàn toàn bởi một luồng:

Tìm kiếm kế hoạch

Đây là kết quả của cách phân phối công việc giữa các luồng bằng các thao tác quét / tìm kiếm song song. Không phải lúc nào việc quét song song sẽ phân phối công việc tốt hơn tìm kiếm chỉ mục - nhưng nó thực hiện trong trường hợp này. Các kế hoạch phức tạp hơn có thể bao gồm các trao đổi phân vùng để phân phối lại công việc giữa các luồng. Kế hoạch này không có trao đổi như vậy, vì vậy một khi các hàng được gán cho một luồng, tất cả các công việc liên quan được thực hiện trên cùng một luồng. Nếu bạn nhìn vào phân phối công việc cho các toán tử khác trong kế hoạch thực hiện, bạn sẽ thấy rằng tất cả các công việc được thực hiện bởi cùng một luồng như được hiển thị cho tìm kiếm chỉ mục.

Không có gợi ý truy vấn nào ảnh hưởng đến phân phối hàng giữa các luồng, điều quan trọng là phải nhận thức được khả năng và có thể đọc đủ chi tiết trong kế hoạch thực hiện để xác định khi nào nó gây ra sự cố.

Với chỉ mục mặc định (chỉ trên khóa chính), tại sao lại mất ít thời gian hơn và với chỉ mục không được nhóm hiện diện, đối với mỗi hàng trong bảng tham gia, hàng bảng tham gia sẽ được tìm thấy nhanh hơn, bởi vì tham gia nằm trên cột Tên trên đó chỉ số đã được tạo. Điều này được phản ánh trong kế hoạch thực hiện truy vấn và chi phí Tìm kiếm Index sẽ ít hơn khi IndexA hoạt động, nhưng tại sao vẫn chậm hơn? Ngoài ra những gì trong Nested Loop bên ngoài tham gia bên ngoài đang gây ra sự chậm lại?

Bây giờ rõ ràng là kế hoạch chỉ mục không bao gồm có khả năng hiệu quả hơn, như bạn mong đợi; nó chỉ là sự phân phối công việc kém qua các luồng trong thời gian thực hiện chiếm vấn đề về hiệu năng.

Để hoàn thành ví dụ và minh họa một số điều tôi đã đề cập, một cách để có được phân phối công việc tốt hơn là sử dụng bảng tạm thời để thực hiện song song:

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;

Điều này dẫn đến một kế hoạch sử dụng chỉ mục tìm kiếm hiệu quả hơn, không có tính năng bộ đệm bảng và phân phối công việc trên các luồng tốt:

Kế hoạch tối ưu

Trên hệ thống của tôi, gói này thực hiện nhanh hơn đáng kể so với phiên bản Clustered Index Scan.

Nếu bạn muốn tìm hiểu thêm về nội bộ của việc thực hiện truy vấn song song, bạn có thể muốn xem bản ghi phiên PASS Summit 2013 của tôi .


0

Nó không thực sự là một câu hỏi về chỉ mục, nó là một truy vấn viết kém hơn. Bạn chỉ có 100 giá trị duy nhất của tên, điều này để lại số lượng duy nhất 5000 cho mỗi tên.

Vì vậy, với mỗi dòng trong bảng 1, bạn sẽ tham gia 5000 từ bảng 2. Bạn có thể nói 25020004 dòng không.

Hãy thử điều này, lưu ý rằng đây chỉ là 1 chỉ mục, chỉ số bạn đã liệt kê.

    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

Và thời gian:

    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.

nhập mô tả hình ảnh ở đây

Bạn không thể đổ lỗi cho các chỉ mục SQL cho các truy vấn được hình thành xấu


1
Cảm ơn câu trả lời, và vâng, truy vấn có thể được cải thiện, nhưng logic của câu hỏi của tôi là với chỉ mục mặc định (chỉ trên khóa chính) tại sao lại mất ít thời gian hơn và với chỉ mục không được phân cụm, cho mỗi hàng trong bảng tham gia, hàng bảng đã tham gia sẽ được tìm thấy nhanh hơn, được phản ánh trong kế hoạch thực hiện truy vấn và chi phí Tìm kiếm Index sẽ ít hơn khi IndexA hoạt động, nhưng tại sao vẫn chậm hơn? Ngoài ra những gì trong Nested Loop bên ngoài tham gia bên ngoài đang gây ra sự chậm lại? Tôi đã chỉnh sửa câu hỏi để thêm nhận xét này, để làm cho câu hỏi rõ ràng hơn.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.