Я пишу в своем следующем блоге о ранжировании и агрегировании оконных функций, в частности, об итераторах Segment и Sequence Project. Насколько я понимаю, Segment идентифицирует строки в потоке, которые составляют конец / начало группы, поэтому следующий запрос:
SELECT ROW_NUMBER() OVER (PARTITION BY someGroup ORDER BY someOrder)
Сегмент будет использовать, чтобы указать, когда строка принадлежит другой группе, отличной от предыдущей строки. Затем итератор проекта последовательности выполняет фактическое вычисление номера строки на основе выходных данных итератора сегмента.
Но следующий запрос, использующий эту логику, не должен включать сегмент, потому что нет выражения раздела.
SELECT ROW_NUMBER() OVER (ORDER BY someGroup, someOrder)
Однако, когда я попробую эту гипотезу, оба этих запроса используют оператор Сегмент. Единственное отличие состоит в том, что второй запрос не нуждается GroupBy
в сегменте. Разве это не устраняет необходимость сегмента в первую очередь?
пример
CREATE TABLE dbo.someTable (
someGroup int NOT NULL,
someOrder int NOT NULL,
someValue numeric(8, 2) NOT NULL,
PRIMARY KEY CLUSTERED (someGroup, someOrder)
);
--- Query 1:
SELECT ROW_NUMBER() OVER (PARTITION BY someGroup ORDER BY someOrder)
FROM dbo.someTable;
--- Query 2:
SELECT ROW_NUMBER() OVER (ORDER BY someGroup, someOrder)
FROM dbo.someTable;
источник
<GroupBy />
поэтому сегмент действительно ничего не делает, почти он выводит столбец сегмента оператору проекта последовательности. Причиной присутствия оператора сегмента может быть то, что оператору проекта последовательности необходимо это значение для выполнения своей работы.Ответы:
Я нашел это 6-летнее сообщение в блоге, упоминающее то же самое поведение.
Похоже,
ROW_NUMBER()
всегда включает в себя оператор сегмента, независимо от тогоPARTITION BY
, используется он или нет. Если бы мне пришлось угадывать, я бы сказал, что это потому, что это облегчает создание плана запросов на движке.Если сегмент нужен в большинстве случаев, а в тех случаях, когда он не нужен, то это, по сути, неоперация с нулевой стоимостью, гораздо проще просто всегда включать его в план при использовании оконной функции.
источник
В соответствии с showplan.xsd для плана выполнения,
GroupBy
отображается без атрибутовminOccurs
илиmaxOccurs
атрибутов, поэтому по умолчанию используется значение [1..1], что делает элемент обязательным, а не обязательно содержимым. Дочерний элементColumnReference
типа (ColumnReferenceType
) имеетminOccurs
0 иmaxOccurs
неограниченный [0 .. *], что делает его необязательным , следовательно, допускается пустой элемент. Если вы вручную попытаетесь удалитьGroupBy
и принудительно ввести план, вы получите ожидаемую ошибку:Интересно, что я обнаружил, что вы можете вручную удалить оператор Сегмент, чтобы получить действительный план форсирования, который выглядит следующим образом:
Однако, когда вы работаете с этим планом (используя
OPTION ( USE PLAN ... )
), Оператор Сегмента волшебным образом появляется снова. Просто показывает, что оптимизатор воспринимает планы XML только как грубое руководство.Мой испытательный стенд:
Извлеките план XML из испытательного стенда и сохраните его как .sqlplan, чтобы просмотреть план без сегмента.
PS Я бы не стал тратить слишком много времени на ручное планирование SQL-планов, так как если бы вы знали меня, вы бы поняли, что я расцениваю это как занятое временем занятие и то, чего я никогда бы не сделал. Ох, подожди !? :)
источник