Зачем нужен этот агрегат потока?

12

Проверьте этот запрос. Это довольно просто (см. В конце поста определения таблиц и индексов, а также скрипт repro):

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

Примечание: «AND 1 = (SELECT 1) просто для того, чтобы этот запрос не был автоматически параметризован, что, как мне показалось, сбивало с толку проблему - он фактически получает тот же план с или без этого предложения, хотя

И вот план ( вставьте ссылку на план) :

план с потоком

Так как там есть «топ 1», я был удивлен, увидев оператор агрегата потока. Это не кажется мне необходимым, поскольку гарантированно будет только один ряд.

Чтобы проверить эту теорию, я попробовал этот логически эквивалентный запрос:

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

Вот план для этого ( вставьте ссылку на план ):

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

Конечно же, группа по плану может обойтись без оператора объединения потоков.

Обратите внимание, что оба запроса читают «назад» из конца индекса и делают «top 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сделало бы его агрегированным вектором, и тогда правильное поведение - не возвращать строки.

Для получения дополнительной информации см. Fun со скалярными и векторными агрегатами .

Мартин Смит
источник