Есть ли какая-либо реальная выгода для итератора катушки в первом плане?
Это зависит от того, что вы считаете «правдоподобным», но ответ в соответствии с моделью затрат - «да». Конечно, это правда, потому что оптимизатор всегда выбирает самый дешевый план, который он находит.
Реальный вопрос заключается в том, почему модель затрат рассматривает план с катушкой намного дешевле, чем план без. Рассмотрим примерные планы, созданные для новой таблицы (из вашего сценария), прежде чем какие-либо строки будут добавлены в дельта-хранилище:
DELETE Fact.RecordedMetricsDetail
WHERE MeasurementTime < DATEADD(day,-1,GETUTCDATE())
OPTION (RECOMPILE);
Ориентировочная стоимость этого плана составляет 771 734 единицы :
Почти все затраты связаны с удалением кластерного индекса, поскольку ожидается, что удаление приведет к большому количеству случайных операций ввода-вывода. Это просто общая логика, которая применяется ко всем модификациям данных. Например, предполагается, что неупорядоченный набор модификаций индекса b-дерева приводит к в значительной степени случайному вводу / выводу с соответствующей высокой стоимостью ввода / вывода.
Планы с изменением данных могут включать сортировку для представления строк в порядке, обеспечивающем последовательный доступ, именно по этим причинам стоимости. В этом случае влияние усугубляется, потому что таблица разделена. Очень разделенный, на самом деле; ваш сценарий создает 15 000 из них. Случайные обновления очень секционированной таблицы стоят особенно дорого, так как цена переключения секций (наборов строк) в середине потока также высока.
Последний важный фактор, который следует учитывать, заключается в том, что простой запрос на обновление выше (где «обновление» означает любую операцию по изменению данных, включая удаление) отвечает требованиям оптимизации, называемой «совместное использование набора строк», где один и тот же внутренний набор строк используется как для сканирования, так и для сканирования. Обновление таблицы. План выполнения по-прежнему показывает два отдельных оператора, но, тем не менее, используется только один набор строк.
Я упоминаю об этом, потому что возможность применять эту оптимизацию означает, что оптимизатор выбирает путь кода, который просто не учитывает потенциальные преимущества явной сортировки для снижения стоимости случайного ввода-вывода. В тех случаях, когда таблица представляет собой b-дерево, это имеет смысл, потому что структура изначально упорядочена, поэтому совместное использование набора строк автоматически обеспечивает все потенциальные выгоды.
Важным следствием является то, что логика калькуляции для оператора обновлений не учитывает это преимущество упорядочения (содействие последовательному вводу / выводу или другие оптимизации), когда базовым объектом является хранилище столбцов. Это связано с тем, что изменения хранилища столбцов не выполняются на месте; они используют дельта-магазин. Следовательно, модель затрат отражает разницу между обновлениями набора общих строк в b-деревьях и хранилищами столбцов.
Тем не менее, в особом случае (очень!) Многораздельного хранилища столбцов может сохраняться преимущество сохраненного упорядочения, поскольку выполнение всех обновлений одного раздела перед переходом к следующему может быть выгодным с точки зрения ввода / вывода. ,
Здесь используется стандартная логика затрат для хранилищ столбцов, поэтому план, который сохраняет порядок разделов (но не порядок внутри каждого раздела), стоит меньше. Мы можем видеть это в тестовом запросе, используя недокументированный флаг трассировки 2332, чтобы потребовать отсортированный ввод для оператора обновления. Это устанавливает для DMLRequestSort
свойства значение true при обновлении и вынуждает оптимизатор создать план, который содержит все строки для одного раздела перед переходом к следующему:
DELETE Fact.RecordedMetricsDetail
WHERE MeasurementTime < DATEADD(day,-1,GETUTCDATE())
OPTION (RECOMPILE, QUERYTRACEON 2332);
Ориентировочная стоимость этого плана намного ниже и составляет 52,5174 единицы:
Это снижение стоимости связано с более низкой оценочной стоимостью ввода-вывода при обновлении. Представленный Spool не выполняет никакой полезной функции, за исключением того, что он может гарантировать вывод в порядке разбиения, как того требует обновление с помощью DMLRequestSort = true
(последовательное сканирование индекса хранилища столбцов не может обеспечить эту гарантию). Стоимость самой катушки считается относительно низкой, особенно по сравнению с (возможно, нереальным) снижением стоимости при обновлении.
Решение о том, требовать ли упорядоченный ввод для оператора обновления, принимается очень рано при оптимизации запросов. Эвристика, использованная в этом решении, никогда не была задокументирована, но может быть определена методом проб и ошибок. Кажется, что размер любого магазина дельты - вход к этому решению. После того, как выбор сделан, выбор является постоянным для компиляции запроса. Никакая USE PLAN
подсказка не будет успешной: цель плана либо заказала входные данные для обновления, либо нет.
Есть другой способ получить недорогой план для этого запроса без искусственного ограничения оценки количества элементов. Достаточно низкая оценка, чтобы избежать Spool, вероятно, приведет к тому, что DMLRequestSort будет ложным, что приведет к очень высокой оценочной стоимости плана из-за ожидаемого случайного ввода-вывода. Альтернативой является использование флага трассировки 8649 (параллельный план) в сочетании с 2332 (DMLRequestSort = true):
DELETE Fact.RecordedMetricsDetail
WHERE MeasurementTime < DATEADD(day,-1,GETUTCDATE())
OPTION (RECOMPILE, QUERYTRACEON 2332, QUERYTRACEON 8649);
Это приводит к плану, который использует параллельное сканирование в пакетном режиме для каждого раздела и сохраняющий порядок (объединение) обмен Gather Streams:
В зависимости от эффективности упорядочения разделов на вашем оборудовании во время выполнения, это может быть лучшим из трех. Тем не менее, большие модификации не являются хорошей идеей в хранилище столбцов, поэтому идея переключения разделов почти наверняка лучше. Если вы можете справиться с длительным временем компиляции и изворотливым выбором планов, часто встречающимся с разделенными объектами - особенно, когда число разделов велико.
Объединение многих относительно новых функций, особенно вблизи их пределов, является отличным способом получить плохие планы выполнения. Глубина поддержки оптимизатора имеет тенденцию улучшаться с течением времени, но использование 15 000 разделов хранилища столбцов, вероятно, всегда будет означать, что вы живете в интересные времена.
OPTION (QUERYRULEOFF EnforceHPandAccCard)
катушка исчезнет. Я полагаю, что HP может быть "Защита Хэллоуина". Однако затем попытка использовать этот план сUSE PLAN
подсказкой не удалась (как и попытка использовать план изOPTIMIZE FOR
обходного пути)