Чому цей агрегат потоків необхідний?


12

Перевірте цей запит. Це досить просто (див. У кінці публікації визначення таблиць та індексів та сценарій репро).

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

Зауважте: "І 1 = (ВИБІР 1) - це просто уникнути автоматичного параметризації цього запиту, що, як мені здається, заплутало проблему - він насправді отримує той самий план із цим пунктом або без нього, хоча

А ось план ( вставте посилання на план) :

план з потоком AGG

Оскільки там є "топ-1", я здивувався, побачивши оператора потокового агрегату. Мені це не здається необхідним, оскільки гарантовано буде лише один ряд.

Щоб перевірити цю теорію, я спробував цей логічно еквівалентний запит:

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

Ось план для цього ( вставте посилання на план ):

план без потокового агг

Звичайно, група за планом може обійтись без оператора агрегату потоку.

Зауважте, що обидва запити читають "назад" з кінця індексу та роблять "верхню 1", щоб отримати максимальну редакцію.

Що я тут пропускаю? Чи поточний агрегат справді працює в першому запиті, чи його можна буде усунути (і це лише обмеження оптимізатора, що це не так)?

До речі, я розумію, що це не є надзвичайно практичною проблемою (обидва запити повідомляють 0 мс процесора та минув час), мені просто цікаво про те, що тут проявляються внутрішні / поведінки.


Ось код налаштування, який я запускав перед тим, як запустити два вищевказані запити:

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

Відповіді:


16

Ви можете бачити роль цього сукупності, якщо жоден рядок не відповідає WHEREпункту.

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

У цьому випадку нульові рядки йдуть у сукупність, але він все одно випромінює один, оскільки правильна семантика повинна повернутися NULLв цьому випадку.

введіть тут опис зображення

Це скалярний агрегат на відміну від векторного.

Ваш "логічно еквівалентний" запит не еквівалентний. Додавання GROUP BY Idзробить це векторним агрегатом і тоді правильною поведінкою було б повернення жодних рядків.

Докладніше про це див. У розділі Розваги зі скалярними та векторними агрегатами .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.