Чи є якась правдоподібна користь для ітератора котушки у першому плані?
Це залежить від того, що ви вважаєте "правдоподібним", але відповідь відповідно до вартісної моделі - так. Звичайно, це правда, адже оптимізатор завжди вибирає найдешевший план, який він знайде.
Справжнє питання полягає в тому, чому модель витрат вважає план із котушкою набагато дешевшим, ніж план без. Розгляньте передбачувані плани, створені для нової таблиці (з вашого сценарію), перш ніж будь-які рядки будуть додані в магазин delta:
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
натяк не вдасться: ціль плану або замовила введення в оновлення, або його немає.
Є ще один спосіб отримати недорогий план цього запиту, не штучно обмежуючи оцінку кардинальності. Досить низька оцінка, щоб уникнути отримання катушки, ймовірно, призведе до помилки DMLRequestSort, що призведе до дуже високої оціночної вартості плану через очікувані випадкові введення / виведення. Альтернативою є використання прапора трассировки 8649 (паралельний план) спільно з 2332 (DMLRequestSort = true):
DELETE Fact.RecordedMetricsDetail
WHERE MeasurementTime < DATEADD(day,-1,GETUTCDATE())
OPTION (RECOMPILE, QUERYTRACEON 2332, QUERYTRACEON 8649);
Це призводить до плану, який використовує паралельне сканування пакетного режиму на розділ та обмін Gather Streams для збереження порядку (об'єднання):
Залежно від ефективності виконання замовлення розділів на вашому обладнання, це може бути найкращим із трьох. Однак, великі модифікації не є чудовою ідеєю щодо зберігання стовпців, тому ідея перемикання розділів майже напевно краща. Якщо ви можете впоратися з довгими часом компіляції та вигадливим вибором плану, що часто спостерігається з об’єктами, що розділяються, особливо коли кількість розділів велика.
Поєднання багатьох, відносно нових, особливостей, особливо поблизу їхніх меж, є чудовим способом отримати погані плани виконання. Глибина підтримки оптимізатора, як правило, з часом покращується, але використання 15000 розділів магазину стовпців, ймовірно, завжди означає, що ви живете в цікаві часи.
OPTION (QUERYRULEOFF EnforceHPandAccCard)
золотник зникає. Я припускаю, що HP може бути "Захистом на Хеллоуїн". Однак потім спроба використати цей план ізUSE PLAN
підказкою не вдається (як і спроба використовувати план зOPTIMIZE FOR
обходу)