Tại sao tối ưu hóa này cho UNKNOWN cải thiện truy vấn của tôi trong vài giây?


7

Ok, vì vậy tôi có một truy vấn thủ tục không được lưu trữ mà chúng tôi đang sử dụng trong báo cáo SSRS. Truy vấn này đã được hellishly chậm (Tôi đã có gốc phiên bản của truy vấn này chạy trong hai giờ qua, vẫn không được thực hiện), trong một nỗ lực để cải thiện nó tôi viết lại nó từ đầu, và tôi đã đưa ra như sau:

Bây giờ đây là phần vấn đề từ nhàm chán:

Chúng tôi muốn kéo một danh sách các TOP 5khách hàng mỗi đại diện bán hàng, nhưng loại trừ các TOP 10tổng khách hàng từ danh sách đó. (Vì vậy, nếu John Doe có khách hàng A, B, C, D và E và khách hàng C là một trong số 10 khách hàng hàng đầu, thì chỉ kéo A, B, D và E.)

Để làm điều này, truy vấn đầu tiên đã sử dụng a IN (... NOT IN ( ) ), vì vậy tôi nghĩ rằng việc lồng vào INlà vấn đề, để viết lại tôi đã làm một OUTER APPLYviệc thực sự phá vỡ mọi thứ.

Dù sao, tôi đã sửa tất cả những thứ đó và tôi chạy truy vấn, và nó vẫn mất 10 - 15 giây mà tôi cho là tham số đánh hơi. Để điều tra, tôi đã chạy truy vấn trong SSMS, được thêm vào OPTION (RECOMPILE)(để xem kế hoạch truy vấn nào sẽ tạo ra) và nhận được thông tin sau:

Kế hoạch 1

Nó có thể được xem ở đây trên 'Dán kế hoạch' của Brent Ozar . Truy vấn đã tạo ra điều này là:

DECLARE @Top10Temp TABLE (Id INT)
INSERT INTO @Top10Temp
SELECT TOP 10 Id
FROM Object1
WHERE Column2  = @ReportId
  AND Column3  = 0
GROUP BY Id
ORDER BY SUM(Column4 + Column5) DESC

SELECT Object2.*
FROM Object1 AS Object2
OUTER APPLY (
    SELECT TOP 5
        Object3.Id,
        SUM(Object3.Column4 + Object3.Column5) AS Column6
    FROM Object1 AS Object3
    WHERE Object3.Column3 = 0
      AND Object3.Column7 = Object2.Column7
      AND Object3.Column2 = @ReportId
    GROUP BY
        Object3.Id
    ORDER BY
        SUM(Object3.Column4 + Object3.Column5) DESC
) AS Object4
WHERE Object2.Column2 =      @ReportId
  AND Object2.Column3 =      0
  AND Object2.Id      =      Object4.Id
  AND Object2.Id      NOT IN (SELECT Id FROM @Top10Temp)
ORDER BY Object2.Column7
OPTION (RECOMPILE)

Bây giờ cùng một truy vấn nhưng với OPTION (OPTIMIZE FOR UNKNOWN)kế hoạch đã tạo:

Kế hoạch 2

Mà cũng có thể được xem tại 'Dán kế hoạch' . Kế hoạch này được thực hiện trong chưa đầy 1 giây.

Nếu tôi thêm OPTION (OPTIMIZE FOR (@ReportId = #)), mà #tương tự như các @ReportIdbiến, tôi nhận được kế hoạch truy vấn giống như thứ hai.

Tôi đã làm gì sai sao? Tôi gặp khó khăn trong việc hiểu những gì đã xảy ra, vì vậy bất kỳ thông tin nào cũng được đánh giá cao. (Tôi cũng thực sự không thích cố gắng tác động đến trình tối ưu hóa thông qua các gợi ý, nhưng nếu cần tôi sẽ giữ nó.)


Bạn đã thử cập nhật số liệu thống kê cho các bảng trong câu hỏi?
Max Vernon

@MaxVernon Có, và nó thực sự không giúp được gì cả. : /
Der Kommissar

Câu trả lời:


5

"Để điều tra tôi đã chạy truy vấn trong SSMS ..." Đó là vấn đề. Các biến cục bộ sử dụng vectơ mật độ thống kê mang lại ước tính hàng tốt hơn nhiều và do đó đã TỐI ƯU HÓA cho UNKNOWN. SQL động được tham số hóa sử dụng biểu đồ, kéo toàn bộ số hàng cho một phần nhất định.

Nhìn vào số lượng ước tính so với số lượng hàng thực tế cho mỗi liên kết Dán Kế hoạch của bạn. Liên kết thứ hai có waaaayyyy ước tính tốt hơn so với liên kết đầu tiên.

Tôi sẽ triển khai truy vấn SSRS của bạn đến một phiên bản dev và chạy một số thử nghiệm vì tôi nghi ngờ bạn có thể có vấn đề về hiệu năng.

BTW, cập nhật số liệu thống kê hoặc xây dựng lại các chỉ mục trên các bảng quái thú đó, nếu bạn có thể.

Liên kết: Bên trong Biểu đồ Thống kê & Mật độ Vector


Vấn đề là các bảng này không lớn (đáng lẽ phải thêm câu hỏi đó), tổng số hàng chỉ là 200.000 và truy vấn trả về số hàng cuối cùng là khoảng 1850 hàng.
Der Kommissar

@ 202_accepted Ngay cả khi bảng không lớn, ước tính không chính xác của các hàng được trả về có thể gây ra các cấp bộ nhớ thực thi, có khả năng gây tranh chấp trên máy chủ và, nếu máy chủ bị tranh chấp tài nguyên thì bộ nhớ càng lớn thì mức độ ưu tiên càng thấp. Nhìn vào kế hoạch thực hiện đầu tiên của bạn (di chuột qua chỉ mục tìm kiếm hoặc quét) và so sánh các hàng ước tính so với hàng thực tế được trả về. Họ đang điên lên! Bây giờ so sánh với kế hoạch thực hiện thứ 2: không tuyệt vời, nhưng ước tính tốt hơn nhiều so với tỷ lệ thực tế. Cuối cùng, kiểm tra gọi truy vấn từ SSRS và cục bộ: khác nhau?
thundercougarfalcon

4

Gói chậm có ước tính cardinality kém xuất phát từ chỉ số tìm kiếm tại nút 4. Số lượng hàng ước tính là 1 nhưng số hàng thực tế là 3261. Đây là vị từ tìm kiếm:

Seek Keys[1]: Prefix: Database1.Schema1.Object1.Column2, Database1.Schema1.Object1.Column3 = Scalar Operator(ScalarString7), Scalar Operator(ScalarString2)

Bạn đang lọc trên hai cột khác nhau từ cùng một bảng. Thông thường SQL Server không có đủ thông tin để đưa ra ước tính chính xác cho kịch bản đó, do đó, nó đưa ra các giả định mô hình hóa phụ thuộc vào phiên bản CE của bạn, các bản vá, cờ theo dõi, v.v. Ví dụ, nó có thể giả định rằng các cột không có mối tương quan và nhân các mức chọn lọc với nhau. Điều đó có thể dẫn đến một ước tính thấp nếu có một số mối tương quan giữa các bộ lọc.

Nói chung tôi sẽ nói rằng nếu bạn có được hiệu suất tốt với ước tính xấu thì có lẽ bạn đã gặp may mắn và may mắn của bạn có thể hết vào một lúc nào đó. Tôi sẽ cố gắng sửa chữa ước tính đó. Tôi không thể cung cấp cho bạn các hướng dẫn chính xác vì thiếu quá nhiều thông tin (bạn sẽ không thể chia sẻ một số thông tin bị thiếu do lo ngại về IP), nhưng tôi có thể nói rằng một thống kê hoặc chỉ mục nhiều cột có thể giúp ích. Lưu trữ các khóa chính của bảng sau khi lọc vào bảng tạm thời là phương pháp luôn luôn hoạt động. Với ước tính chính xác hơn, tôi sẽ thấy một kế hoạch truy vấn tương tự như kế hoạch nhanh.

Bạn đã không làm gì sai bằng cách thêm OPTION (RECOMPILE)gợi ý. Bạn có thể đã nhận được hiệu suất kém chỉ đơn giản là do xui xẻo. Tối ưu hóa nhúng tham số thường giúp thay vì gây ra vấn đề. OPTIMIZE FOR UNKNOWNkhiến SQL Server sử dụng các đối tượng thống kê khác nhau và điều đó xảy ra khiến bạn có ước tính gần với thực tế hơn khi sử dụng nó.

Tôi sẽ không sử dụng OPTIMIZE FOR UNKNOWNnhư một giải pháp lâu dài. Gói truy vấn sẽ không thay đổi tùy thuộc vào giá trị @ReportIdcó thể gây ra sự cố khi bạn thay đổi giá trị của biến. Đó cũng là một chút sửa chữa gián tiếp và bạn thừa nhận rằng bạn không hiểu cách thức hoạt động của nó. Sẽ là tốt hơn để tấn công vấn đề trực tiếp hơn bằng cách sửa ước tính cardinality hoặc bằng cách chiến lược cụ thể hóa các kết quả trung gian vào các bảng tạm thời. Theo nguyên tắc chung, bạn nên tránh sử dụng các biến bảng vì chúng không có số liệu thống kê. Biến bảng có các trường hợp sử dụng rất hạn chế và khuyến nghị của tôi cho bạn là chỉ sử dụng chúng khi bạn không có lựa chọn nào khác.


Tôi đánh giá cao câu trả lời chi tiết này Joe và tôi chỉ có một câu hỏi: có cách nào để gợi ý cho SQL Server rằng mỗi câu hỏi @ReportIdsẽ có cùng số kết quả không? (Họ nên trong vòng 5-20 hàng của nhau.) Tôi không biết nếu mà có thể giúp tình hình của tôi hay không, hoặc nếu nó thậm chí còn có thể, nhưng đó là một điều mà tôi có thể thấy có một tác động.
Der Kommissar

1
@ 202_accepted Bạn có hỏi về cột mà ReportId lọc không? Nếu biểu đồ cho cột thể hiện dữ liệu của bạn đủ tốt thì điều đó không cần thiết. Nếu không, bạn có thể cố gắng chọn một giá trị đại diện để sử dụng với TỐI ƯU HÓA GIÁ TRỊ nhưng biểu đồ của bạn có thể thay đổi theo thời gian. Nếu bạn muốn sử dụng mật độ thì bạn có thể sử dụng TỐI ƯU HÓA CHO UNKNOWN cùng với TỐI ƯU HÓA GIÁ TRỊ cho mọi thứ khác, nhưng có thể cho rằng đó không phải là gợi ý được thiết kế cho.
Joe Obbish

Tôi đồng ý với Joe. Tìm kiếm hướng dẫn kế hoạch cho mir Chi tiết và tùy chọn. technet.microsoft.com/en-us/l
Library / từ
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.