Khi nào các biến vị ngữ SARGable có thể được đẩy vào CTE hoặc bảng dẫn xuất?


15

Bao cát

Trong khi làm việc trên Top Chất lượng Blog Posts®, tôi đi qua một số hành vi ưu tôi thấy thực sự phẩn nộ thú vị. Tôi không có lời giải thích ngay lập tức, ít nhất không phải là một người tôi hài lòng, vì vậy tôi sẽ đưa nó vào đây trong trường hợp ai đó thông minh xuất hiện.

Nếu bạn muốn theo dõi, bạn có thể lấy phiên bản 2013 của kết xuất dữ liệu Stack Overflow tại đây . Tôi đang sử dụng bảng Nhận xét, với một chỉ mục bổ sung trên đó.

CREATE INDEX [ix_ennui] ON [dbo].[Comments] ( [UserId], [Score] DESC );

Truy vấn một

Khi tôi truy vấn bảng như vậy, tôi nhận được một kế hoạch truy vấn kỳ lạ .

WITH x
    AS
     (
         SELECT   TOP 101
                  c.UserId, c.Text, c.Score
         FROM     dbo.Comments AS c
         ORDER BY c.Score DESC
     )
SELECT *
FROM   x
WHERE  x.Score >= 500;

QUẢ HẠCH

Vị từ SARGable trên Điểm không được đẩy vào bên trong CTE. Đó là trong một toán tử lọc nhiều sau đó trong kế hoạch.

QUẢ HẠCH

Mà tôi thấy kỳ lạ, vì ORDER BY trên cùng một cột với bộ lọc.

Truy vấn hai

Nếu tôi thay đổi truy vấn, nó sẽ bị đẩy.

WITH x
    AS
     (
         SELECT   c.UserId, c.Text, c.Score
         FROM     dbo.Comments AS c
     )
SELECT TOP 101 *
FROM   x
WHERE  x.Score >= 500
ORDER BY x.Score DESC;

Các kế hoạch truy vấn thay đổi , quá, và chạy nhanh hơn nhiều, không có tràn vào đĩa. Cả hai đều tạo ra kết quả giống nhau, với vị từ khi quét chỉ mục không bao gồm.

QUẢ HẠCH

QUẢ HẠCH

Truy vấn ba

Điều này tương đương với việc viết truy vấn như vậy:

SELECT   TOP 101
         c.UserId, c.Text, c.Score
FROM     dbo.Comments AS c
WHERE c.Score >= 500
ORDER BY c.Score DESC;

Truy vấn bốn

Sử dụng bảng dẫn xuất sẽ có cùng một kế hoạch truy vấn "xấu" như truy vấn CTE ban đầu

SELECT *
FROM   (   SELECT   TOP 101
                    c.UserId, c.Text, c.Score
           FROM     dbo.Comments AS c
           ORDER BY c.Score DESC ) AS x
WHERE x.Score >= 500;

Mọi thứ trở nên kỳ lạ hơn khi ...

Tôi thay đổi truy vấn để sắp xếp dữ liệu tăng dần và bộ lọc thành <=.

Để tránh làm cho câu hỏi này quá dài, tôi sẽ đặt mọi thứ lại với nhau.

Truy vấn

--Derived table
SELECT *
FROM   (   SELECT   TOP 101
                    c.UserId, c.Text, c.Score
           FROM     dbo.Comments AS c
           ORDER BY c.Score ASC ) AS x
WHERE x.Score <= 500;


--TOP inside CTE
WITH x
    AS
     (
         SELECT   TOP 101
                  c.UserId, c.Text, c.Score
         FROM     dbo.Comments AS c
         ORDER BY c.Score ASC
     )
SELECT *
FROM   x
WHERE  x.Score <= 500;


--Written normally
SELECT   TOP 101
         c.UserId, c.Text, c.Score
FROM     dbo.Comments AS c
WHERE c.Score <= 500
ORDER BY c.Score ASC;

--TOP outside CTE
WITH x
    AS
     (
         SELECT   c.UserId, c.Text, c.Score
         FROM     dbo.Comments AS c
     )
SELECT TOP 101 *
FROM   x
WHERE  x.Score <= 500
ORDER BY x.Score ASC;

Các kế hoạch

Kế hoạch liên kết .

QUẢ HẠCH

Lưu ý rằng không có truy vấn nào trong số các truy vấn này tận dụng chỉ mục không bao gồm - điều duy nhất thay đổi ở đây là vị trí của toán tử bộ lọc. Trong mọi trường hợp là vị từ được đẩy đến truy cập chỉ mục.

Một câu hỏi xuất hiện!

Có một lý do mà một vị từ SARGable có thể được đẩy trong một số tình huống và không phải trong các tình huống khác? Sự khác biệt trong các truy vấn được sắp xếp theo thứ tự giảm dần rất thú vị, nhưng sự khác biệt giữa những truy vấn và những thứ đang tăng dần kỳ quái.

Đối với bất kỳ ai quan tâm, đây là các kế hoạch chỉ có một chỉ mục trên Score:

Câu trả lời:


11

Có một vài vấn đề trong chơi ở đây.

Đẩy vị ngữ quá khứ TOP

Trình tối ưu hóa hiện không thể đẩy một vị từ đi qua a TOP, ngay cả trong các trường hợp giới hạn trong trường hợp an toàn để làm như vậy *. Giới hạn này chiếm hành vi của tất cả các truy vấn trong câu hỏi trong đó vị từ nằm trong phạm vi cao hơn TOP.

Công việc xung quanh là thực hiện viết lại bằng tay. Vấn đề cơ bản tương tự như trường hợp đẩy các vị từ qua chức năng cửa sổ , ngoại trừ không có quy tắc chuyên ngành tương ứng như thế nào SelOnSeqPrj.

Ý kiến ​​cá nhân của tôi là một quy tắc thăm dò như SelOnTopvẫn chưa được thực hiện bởi vì mọi người đã cố tình viết các truy vấn bằng TOPmột nỗ lực để cung cấp một loại 'hàng rào tối ưu hóa'.

* Nói chung, điều này có nghĩa là vị ngữ sẽ xuất hiện trong ORDER BYmệnh đề được liên kết với TOPvà hướng của bất kỳ bất đẳng thức nào sẽ phù hợp với hướng sắp xếp. Việc chuyển đổi cũng cần tính đến hành vi sắp xếp của các NULL trong SQL Server. Nhìn chung, những hạn chế có thể có nghĩa là sự chuyển đổi này thường không đủ hữu ích trong thực tế để biện minh cho những nỗ lực thăm dò bổ sung.

Vấn đề chi phí

Các kế hoạch thực hiện còn lại trong câu hỏi có thể được giải thích là các lựa chọn dựa trên chi phí do phân phối các giá trị trong Scorecột (nhiều hàng hơn <= 500 so với> = 500) và hiệu quả của mục tiêu hàng được giới thiệu bởi TOP.

Ví dụ: truy vấn:

--Written normally
SELECT TOP (101)
    c.UserId, 
    c.[Text],
    c.Score
FROM dbo.Comments AS c
WHERE
    c.Score <= 500
ORDER BY
    c.Score ASC;

... Tạo ra một kế hoạch với một vị từ dường như chưa được đánh dấu trong Bộ lọc:

bộ lọc muộn do mục tiêu hàng

Lưu ý rằng Sắp xếp được ước tính để tạo ra 101 hàng. Đây là hiệu ứng của mục tiêu hàng được thêm bởi Top. Điều này ảnh hưởng đến chi phí ước tính của Sắp xếp và Bộ lọc đủ để làm cho có vẻ như đây là tùy chọn rẻ hơn. Chi phí ước tính của kế hoạch này là 2401,39 đơn vị.

Nếu chúng tôi vô hiệu hóa mục tiêu hàng với một gợi ý truy vấn:

--Written normally
SELECT TOP (101)
    c.UserId, 
    c.[Text],
    c.Score
FROM dbo.Comments AS c
WHERE
    c.Score <= 500
ORDER BY
    c.Score ASC
OPTION (USE HINT ('DISABLE_OPTIMIZER_ROWGOAL'));

... kế hoạch thực hiện được tạo ra là:

kế hoạch không có mục tiêu hàng

Vị từ đã được đẩy vào quá trình quét dưới dạng một vị từ không thể bỏ qua còn lại và chi phí của toàn bộ kế hoạch là 2402,32 đơn vị.

Lưu ý rằng <= 500vị ngữ không được mong đợi để lọc ra bất kỳ hàng nào. Nếu bạn đã chọn một số nhỏ hơn, như <= 50, trình tối ưu hóa sẽ ưu tiên kế hoạch đẩy vị ngữ bất kể hiệu ứng mục tiêu hàng.

Đối với truy vấn có Score DESCvà một Score >= 500vị ngữ:

--Written normally
SELECT TOP (101)
    c.UserId, 
    c.[Text],
    c.Score
FROM dbo.Comments AS c
WHERE
    c.Score >= 500
ORDER BY
    c.Score DESC;

Bây giờ vị từ được dự kiến ​​sẽ rất chọn lọc, vì vậy trình tối ưu hóa chọn đẩy vị từ sử dụng chỉ mục không bao gồm với tra cứu:

vị ngữ chọn lọc

Một lần nữa, trình tối ưu hóa đã xem xét nhiều lựa chọn thay thế và chọn đây là lựa chọn rẻ nhất, như thường lệ.

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.