Database
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Database

Các giai đoạn tối ưu hóa và các cơ hội bị bỏ lỡ

Có hai kỹ năng bổ sung rất hữu ích trong việc điều chỉnh truy vấn. Một là khả năng đọc và diễn giải các kế hoạch thực thi. Thứ hai là biết một chút về cách hoạt động của trình tối ưu hóa truy vấn để dịch văn bản SQL thành một kế hoạch thực thi. Kết hợp hai điều lại với nhau có thể giúp chúng tôi phát hiện ra những thời điểm không áp dụng tối ưu hóa dự kiến, dẫn đến kế hoạch thực thi không hiệu quả như mong đợi. Tuy nhiên, việc thiếu tài liệu về chính xác những tối ưu hóa nào mà SQL Server có thể áp dụng (và trong những trường hợp nào) có nghĩa là rất nhiều điều cần phải trải nghiệm.

Một ví dụ

Truy vấn mẫu cho bài viết này dựa trên câu hỏi được hỏi bởi SQL Server MVP Fabiano Amorim vài tháng trước, dựa trên một vấn đề trong thế giới thực mà anh ta gặp phải. Lược đồ và truy vấn thử nghiệm bên dưới là sự đơn giản hóa tình huống thực tế, nhưng nó vẫn giữ lại tất cả các tính năng quan trọng.

CREATE TABLE dbo.T1 (pk integer PRIMARY KEY, c1 integer NOT NULL);
CREATE TABLE dbo.T2 (pk integer PRIMARY KEY, c1 integer NOT NULL);
CREATE TABLE dbo.T3 (pk integer PRIMARY KEY, c1 integer NOT NULL);
GO
CREATE INDEX nc1 ON dbo.T1 (c1);
CREATE INDEX nc1 ON dbo.T2 (c1);
CREATE INDEX nc1 ON dbo.T3 (c1);
GO
CREATE VIEW dbo.V1
AS
    SELECT c1 FROM dbo.T1
    UNION ALL
    SELECT c1 FROM dbo.T2
    UNION ALL
    SELECT c1 FROM dbo.T3;
GO
-- The test query
SELECT MAX(c1)
FROM dbo.V1;

Kiểm tra 1 - 10.000 hàng, SQL Server 2005+

Dữ liệu bảng cụ thể không thực sự quan trọng đối với các thử nghiệm này. Các truy vấn sau chỉ cần tải 10.000 hàng từ một bảng số vào từng bảng trong số ba bảng kiểm tra:

INSERT dbo.T1 (pk, c1)
SELECT n, n
FROM dbo.Numbers AS N
WHERE n BETWEEN 1 AND 10000;
 
INSERT dbo.T2 (pk, c1)
SELECT pk, c1 FROM dbo.T1;
 
INSERT dbo.T3 (pk, c1)
SELECT pk, c1 FROM dbo.T1;


Với dữ liệu được tải, kế hoạch thực thi được tạo cho truy vấn thử nghiệm là:

SELECT MAX(c1) FROM dbo.V1;

Kế hoạch thực thi này là một triển khai khá trực tiếp của truy vấn SQL logic (sau khi tham chiếu dạng xem V1 được mở rộng). Trình tối ưu hóa nhìn thấy truy vấn sau khi mở rộng chế độ xem, gần như thể truy vấn đã được viết ra toàn bộ:

SELECT MAX(c1)
FROM
(
    SELECT c1 FROM dbo.T1
    UNION ALL
    SELECT c1 FROM dbo.T2
    UNION ALL
    SELECT c1 FROM dbo.T3
) AS V1;

So sánh văn bản mở rộng với kế hoạch thực thi, rõ ràng tính trực tiếp của việc triển khai trình tối ưu hóa truy vấn. Có một bản quét chỉ mục cho mỗi lần đọc các bảng cơ sở, một toán tử ghép nối để triển khai UNION ALL và Tổng hợp luồng cho MAX cuối cùng tổng hợp.

Các thuộc tính kế hoạch thực thi cho thấy rằng tối ưu hóa dựa trên chi phí đã được bắt đầu (mức tối ưu hóa là FULL ), nhưng nó đã kết thúc sớm bởi vì một kế hoạch "đủ tốt" đã được tìm thấy. Chi phí ước tính của kế hoạch đã chọn là 0,1016240 đơn vị tối ưu hóa ma thuật.

Kiểm tra 2 - 50.000 hàng, SQL Server 2008 và 2008 R2

Chạy tập lệnh sau để đặt lại môi trường thử nghiệm để chạy với 50.000 hàng:

TRUNCATE TABLE dbo.T1;
TRUNCATE TABLE dbo.T2;
TRUNCATE TABLE dbo.T3;
 
INSERT dbo.T1 (pk, c1)
SELECT n, n
FROM dbo.Numbers AS N
WHERE n BETWEEN 1 AND 50000;
 
INSERT dbo.T2 (pk, c1)
SELECT pk, c1 FROM dbo.T1;
 
INSERT dbo.T3 (pk, c1)
SELECT pk, c1 FROM dbo.T1;
 
SELECT MAX(c1) 
FROM dbo.V1;

Kế hoạch thực thi cho bài kiểm tra này phụ thuộc vào phiên bản SQL Server bạn đang chạy. Trong SQL Server 2008 và 2008 R2, chúng tôi nhận được kế hoạch sau:

Các thuộc tính kế hoạch cho thấy rằng tối ưu hóa dựa trên chi phí vẫn kết thúc sớm vì lý do tương tự như trước đây. Chi phí ước tính cao hơn trước đây là 0,41375 nhưng điều đó được mong đợi do số lượng bảng cơ sở cao hơn.

Kiểm tra 3 - 50.000 hàng, SQL Server 2005 và 2012

Cùng một truy vấn chạy vào năm 2005 hoặc 2012 tạo ra một kế hoạch thực thi khác:

Quá trình tối ưu hóa lại kết thúc sớm, nhưng chi phí kế hoạch ước tính cho 50.000 hàng trên mỗi bảng cơ sở giảm xuống còn 0,0098585 (từ 0,41375 trên SQL Server 2008 và 2008 R2).

Giải thích

Như bạn có thể biết, trình tối ưu hóa truy vấn SQL Server tách nỗ lực tối ưu hóa thành nhiều giai đoạn, với các giai đoạn sau sẽ bổ sung nhiều kỹ thuật tối ưu hóa hơn và cho phép nhiều thời gian hơn. Các giai đoạn tối ưu hóa là:

  • Kế hoạch tầm thường
  • Tối ưu hoá dựa trên chi phí
    • Xử lý giao dịch (tìm kiếm 0)
    • Kế hoạch Nhanh (tìm kiếm 1)
    • Lập kế hoạch nhanh với tính năng song song được bật
    • Tối ưu hoá Toàn bộ (tìm kiếm 2)

Không có thử nghiệm nào được thực hiện ở đây đủ điều kiện cho một kế hoạch tầm thường bởi vì tập hợp và liên kết có nhiều khả năng triển khai, yêu cầu quyết định dựa trên chi phí.

Xử lý giao dịch

Giai đoạn Xử lý giao dịch (TP) yêu cầu truy vấn chứa ít nhất ba tham chiếu bảng, nếu không, tối ưu hóa dựa trên chi phí sẽ bỏ qua giai đoạn này và chuyển thẳng sang Kế hoạch nhanh. Giai đoạn TP nhằm vào các truy vấn điều hướng chi phí thấp điển hình của khối lượng công việc OLTP. Nó thử một số kỹ thuật tối ưu hóa có giới hạn và chỉ giới hạn trong việc tìm kiếm các kế hoạch có Tham gia vòng lặp lồng nhau (trừ khi cần có Tham gia băm để tạo ra một kế hoạch hợp lệ).

Ở một số khía cạnh, điều đáng ngạc nhiên là truy vấn kiểm tra đủ điều kiện cho một giai đoạn nhằm tìm kiếm các kế hoạch OLTP. Mặc dù truy vấn chứa ba tham chiếu bảng được yêu cầu, nhưng nó không chứa bất kỳ phép nối nào. Yêu cầu của ba bảng chỉ là một sự phỏng đoán, vì vậy tôi sẽ không quan tâm đến vấn đề này.

Các Giai đoạn Trình Tối ưu hoá Đã Chạy?

Có một số phương pháp, phương pháp được ghi lại là để so sánh nội dung của sys.dm_exec_query_optimizer_info trước và sau khi biên dịch. Điều này là tốt, nhưng nó ghi lại thông tin toàn phiên bản, vì vậy bạn cần phải cẩn thận rằng của bạn là biên dịch truy vấn duy nhất xảy ra giữa các lần chụp nhanh.

Một giải pháp thay thế không có tài liệu (nhưng khá nổi tiếng) hoạt động trên tất cả các phiên bản SQL Server hiện được hỗ trợ là bật cờ theo dõi 8675 và 3604 trong khi biên dịch truy vấn.

Thử nghiệm 1

Thử nghiệm này tạo ra đầu ra cờ theo dõi 8675 tương tự như sau:

Chi phí ước tính là 0,101624 sau giai đoạn TP đủ thấp để trình tối ưu hóa không tiếp tục tìm kiếm các gói rẻ hơn. Phương án đơn giản mà chúng tôi đưa ra là khá hợp lý với số lượng bảng cơ sở tương đối thấp, ngay cả khi nó không thực sự tối ưu.

Bài kiểm tra 2

Với 50.000 hàng trong mỗi bảng cơ sở, cờ theo dõi tiết lộ thông tin khác nhau:

Lần này, chi phí ước tính sau giai đoạn TP là 0,428735 (nhiều hàng hơn =chi phí cao hơn). Điều này đủ để khuyến khích trình tối ưu hóa bước vào giai đoạn Lập kế hoạch nhanh. Với nhiều kỹ thuật tối ưu hóa hơn có sẵn, giai đoạn này tìm thấy một kế hoạch có chi phí là 0,41375 . Điều này không đại diện cho sự cải thiện lớn so với kế hoạch thử nghiệm 1, nhưng nó thấp hơn ngưỡng chi phí mặc định cho tính song song và không đủ để nhập Tối ưu hóa hoàn toàn, vì vậy tối ưu hóa lại kết thúc sớm.

Bài kiểm tra 3

Đối với SQL Server 2005 và 2012 chạy, đầu ra cờ theo dõi là:

Có sự khác biệt nhỏ về số lượng tác vụ chạy giữa các phiên bản, nhưng sự khác biệt quan trọng là trên SQL Server 2005 và 2012, giai đoạn Kế hoạch nhanh tìm thấy một kế hoạch có giá chỉ 0,0098543 các đơn vị. Đây là kế hoạch chứa các toán tử Hàng đầu thay vì ba Tổng hợp Dòng bên dưới toán tử Kết hợp được thấy trong các kế hoạch SQL Server 2008 và 2008 R2.

Lỗi và Bản sửa lỗi không có tài liệu

SQL Server 2008 và 2008 R2 có một lỗi hồi quy (so với năm 2005) đã được sửa dưới cờ theo dõi 4199, nhưng không được ghi lại theo như tôi có thể nói. Có tài liệu cho TF 4199 liệt kê các bản sửa lỗi được cung cấp dưới các cờ theo dõi riêng biệt trước khi được đề cập bởi 4199, nhưng như bài viết trong Cơ sở Kiến thức cho biết:

Một cờ theo dõi này có thể được sử dụng để kích hoạt tất cả các bản sửa lỗi đã được thực hiện trước đó cho bộ xử lý truy vấn dưới nhiều cờ theo dõi. Ngoài ra, tất cả các bản sửa lỗi của bộ xử lý truy vấn trong tương lai sẽ được kiểm soát bằng cách sử dụng cờ theo dõi này.

Lỗi trong trường hợp này là một trong những "bản sửa lỗi của bộ xử lý truy vấn trong tương lai". Một quy tắc tối ưu hóa cụ thể, ScalarGbAggToTop , không được áp dụng cho các tổng thể mới trong kế hoạch thử nghiệm 2. Với cờ theo dõi 4199 được bật trên các bản dựng phù hợp của SQL Server 2008 và 2008 R2, lỗi đã được sửa và phương án tối ưu từ thử nghiệm 3 sẽ thu được:

-- Trace flag 4199 required for 2008 and 2008 R2
SELECT MAX(c1) 
FROM dbo.V1
OPTION (QUERYTRACEON 4199);

Kết luận

Khi bạn biết rằng trình tối ưu hóa có thể biến đổi một MIN vô hướng hoặc MAX tổng hợp thành một TOP (1) trên một luồng có thứ tự, kế hoạch được hiển thị trong thử nghiệm 2 có vẻ lạ. Tính vô hướng tổng hợp phía trên quá trình quét chỉ mục (có thể cung cấp thứ tự nếu được yêu cầu làm như vậy) nổi bật như một tối ưu hóa bị thiếu thường được áp dụng.

Đây là điểm tôi đã đưa ra trong phần giới thiệu:một khi bạn cảm nhận được nhiều thứ mà trình tối ưu hóa có thể làm, nó có thể giúp bạn nhận ra những trường hợp có gì đó không ổn.

Câu trả lời sẽ không phải lúc nào cũng là bật cờ theo dõi 4199, vì bạn có thể gặp các vấn đề chưa được khắc phục. Bạn cũng có thể không muốn các bản sửa lỗi QP khác được bao phủ bởi cờ theo dõi áp dụng trong một trường hợp cụ thể - các bản sửa lỗi của trình tối ưu hóa không phải lúc nào cũng làm cho mọi thứ tốt hơn. Nếu họ đã làm như vậy, sẽ không cần phải bảo vệ khỏi sự thoái lui kế hoạch đáng tiếc bằng cách sử dụng cờ này.

Giải pháp trong các trường hợp khác có thể là tạo công thức truy vấn SQL bằng cách sử dụng cú pháp khác, để chia nhỏ truy vấn thành nhiều phần thân thiện với trình tối ưu hóa hơn hoặc hoàn toàn khác. Dù câu trả lời là gì, bạn vẫn nên biết một chút về nội bộ của trình tối ưu hóa để bạn có thể nhận ra rằng đã có sự cố ngay từ đầu :)


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cách tránh chèn các bản ghi trùng lặp trong truy vấn SQL INSERT (5 cách dễ dàng)

  2. 13 bài viết trên blog về các thủ thuật và phương pháp thiết kế cơ sở dữ liệu tốt nhất

  3. Tạo kế hoạch bảo trì cơ sở dữ liệu

  4. Tiếp theo về Summer Performance Palooza 2013

  5. Ký hiệu Barker