Tại sao luồng này tổng hợp cần thiết?


12

Kiểm tra truy vấn này. Điều này khá đơn giản (xem phần cuối của bài đăng để biết định nghĩa bảng và chỉ mục và tập lệnh repro):

SELECT MAX(Revision)
FROM dbo.TheOneders
WHERE Id = 1 AND 1 = (SELECT 1);

Lưu ý: "VÀ 1 = (CHỌN 1) chỉ để giữ cho truy vấn này không bị tự động tham số hóa, mà tôi cảm thấy như đang nhầm lẫn vấn đề - mặc dù thực tế nó có cùng một kế hoạch với hoặc không có mệnh đề đó

Và đây là kế hoạch ( dán liên kết kế hoạch) :

kế hoạch với một luồng agg

Vì có "top 1" ở đó, tôi rất ngạc nhiên khi thấy toán tử tổng hợp luồng. Nó dường như không cần thiết đối với tôi, vì được đảm bảo chỉ có một hàng.

Để kiểm tra lý thuyết đó, tôi đã thử truy vấn tương đương logic này:

SELECT MAX(Revision)
FROM dbo.TheOneders
WHERE Id = 1
GROUP BY Id;

Đây là kế hoạch cho cái đó ( dán liên kết kế hoạch ):

kế hoạch mà không có một luồng agg

Chắc chắn, nhóm theo kế hoạch có thể nhận được mà không cần toán tử tổng hợp luồng.

Lưu ý rằng cả hai truy vấn đều đọc "ngược" từ cuối chỉ mục và thực hiện "top 1" để có được sửa đổi tối đa.

Tôi đang thiếu gì ở đây? Là tập hợp luồng thực sự làm việc trong truy vấn đầu tiên, hay nó có thể bị loại bỏ (và đó chỉ là một giới hạn của trình tối ưu hóa mà không phải vậy)?

Nhân tiện, tôi nhận ra đây không phải là một vấn đề thực tế đến khó tin (cả hai truy vấn đều báo cáo 0 ms CPU và thời gian trôi qua), tôi chỉ tò mò về nội bộ / hành vi được thể hiện ở đây.


Đây là mã thiết lập tôi đã chạy trước khi chạy hai truy vấn trên:

DROP TABLE IF EXISTS dbo.TheOneders;
GO

CREATE TABLE dbo.TheOneders
(
    Id INT NOT NULL,
    Revision SMALLINT NOT NULL,
    Something NVARCHAR(23),

    CONSTRAINT PK_TheOneders PRIMARY KEY NONCLUSTERED (Id, Revision)
);
GO

INSERT INTO dbo.TheOneders
    (Id, Revision, Something)
SELECT DISTINCT TOP 1000 
    1, m.message_id, 'Do...'
FROM sys.messages m
ORDER BY m.message_id
OPTION (MAXDOP 1);

INSERT INTO dbo.TheOneders
    (Id, Revision, Something)
SELECT DISTINCT TOP 100 
    2, m.message_id, 'Do that thing you do...'
FROM sys.messages m
ORDER BY m.message_id
OPTION (MAXDOP 1);
GO

Câu trả lời:


16

Bạn có thể thấy vai trò của tổng hợp này nếu không có hàng nào khớp với WHEREmệnh đề.

SELECT MAX(Revision)
FROM   dbo.TheOneders
WHERE  Id = 1
       AND 1 = 1 /*To avoid auto parameterisation*/
       AND Id%3 = 4  /*always false*/

Trong trường hợp đó, không có hàng nào đi vào tổng hợp nhưng nó vẫn phát ra một hàng như ngữ nghĩa chính xác sẽ trả về NULLtrong trường hợp này.

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

Đây là một tổng hợp vô hướng trái ngược với một vectơ.

Truy vấn "tương đương logic" của bạn không tương đương. Việc thêm vào GROUP BY Idsẽ làm cho nó trở thành một tổng hợp vectơ và sau đó hành vi đúng sẽ là không trả về hàng nào.

Xem Vui với Tổng hợp vô hướng và Vector để biết thêm về điều này.

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.