Чому оцінки рядків SQL Server змінюються, коли я додаю підказку про приєднання?


15

У мене є запит, який поєднує декілька таблиць і виконує досить погано - оцінки рядків відключаються (в 1000 разів) і вибирається об'єднання вкладених циклів, в результаті чого відбувається багаторазове сканування таблиці. Форма запиту досить проста, виглядає приблизно так:

SELECT t1.id
FROM t1
INNER JOIN t2 ON t1.id = t2.t1_id
LEFT OUTER JOIN t3 ON t2.id = t3.t2_id
LEFT OUTER JOIN t4 ON t3.t4_id = t4.id 
WHERE t4.id = some_GUID

Граючи з запитом, я помітив, що коли я натякаю йому на використання об'єднання Merge для одного з об'єднань, він працює в багато разів швидше. Це я можу зрозуміти - Об'єднання об'єднань є кращим варіантом даних, які об’єднуються, але SQL Server просто не оцінює його правильним вибором вкладених циклів.

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

Однак я бачу, що натяк на об'єднання змушує всі оцінки стати ідеальними. Чому це відбувається і чи є якісь загальні методи, щоб оптимізатор запитів зробив кращу оцінку без натяку - враховуючи, що статистика, очевидно, це дозволяє?

UPD: анонімізовані плани виконання можна знайти тут: https://www.dropbox.com/s/hchfuru35qqj89s/merge_join.sqlplan?dl=0 https://www.dropbox.com/s/38sjtv0t7vjjfdp/no_hints_join.sqlplan?dl = 0

Я перевірив статистику, використовувану обома запитами за допомогою TF 3604, 9292 та 9204, і ці дані однакові. Однак індекси, які скануються / шукаються, відрізняються між запитами.

Крім того, я спробував запустити запит за допомогою OPTION (FORCE ORDER)- він працює навіть швидше, ніж використовувати об'єднання об'єднань, вибравши HASH MATCH для кожного приєднання.


3
Ви помітили, що у вас є зовнішнє з'єднання, але ви використовуєте таблицю в пункті де?
Джеймс Z

@JamesZ - так, я знаю про це, але я не думаю, що в цьому є проблеми.
Олександр Шелемін

9
@AlexSh Ну, є логічна / семантична проблема з цим, оскільки це змінює ваше зовнішнє з'єднання на внутрішнє з'єднання.
Аарон Бертран

Відповіді:


21

Читаючи різні статті та книги, я припустив, що оцінки кардинальності виконуються до того, як побудований план.

Не зовсім. Первісна оцінка потужності (після спрощень та інших робіт), яка впливає на початковий порядок з'єднання, обраний оптимізатором.

Однак наступні дослідження (під час оптимізації, засновані на витратах) можуть, а часто і призводять до обчислення нових оцінок кардинальності. Ці пізні КЕ можуть бути більш-менш "точними". Якщо результати недооцінені, оптимізатор може вибрати план, який виглядає дешевше, але насправді працює набагато довше.

Загалом, немає гарантії, що оцінки кардинальності для семантично однакових підрядів дадуть однакові результати. Зрештою, це статистичний процес, і деякі операції мають більш глибоку підтримку СЕ, ніж інші.

У вашому випадку, здається, є ще один фактор - оптимізатор вводить (або рухається навколо) Top, який встановлює мету рядка на піддереві під ним:

Фрагмент плану

Якщо ви б увімкнули прапор трассирування 4138 (на 2008 R2 або новіших версій), ви можете знайти оцінки, що відповідають вимогам, а можливо, навіть, що оптимізатор більше не вибере вкладені петлі.

Однак я бачу, що натяк на об'єднання змушує всі оцінки стати ідеальними.

Тут задіяний елемент удачі. Люди схильні писати запити чи принаймні приєднання в тому порядку, коли вони очікують, що їх буде виконано фізично. Використання підказки про приєднання постачається з неявним FORCE ORDER, тим самим фіксуючи порядок з'єднання відповідно до текстової форми та вимикаючи безліч правил дослідження оптимізатора, що може призвести до переоцінки кардинальності.

Крім того, я спробував запустити запит за допомогою OPTION (FORCE ORDER)- він працює навіть швидше, ніж використовувати об'єднання об'єднань, вибравши HASH MATCH для кожного приєднання.

Це те саме, що натякає на приєднання, але не обмежує вибір фізичного оператора приєднання. Знову ж таки, якщо вам трапилося написати запит на приєднання до логіки, цілком ймовірно, ви отримаєте розумний план. Звичайно, ви втрачаєте багато можливостей оптимізатора таким чином, що може не давати оптимальних результатів у більш загальних ситуаціях.

Ви, мабуть, не захочете користуватися FORCE ORDERдуже часто, тому що це надзвичайно потужна підказка (директива), яка має ширші ефекти, ніж просте примушування порядку вступу; наприклад, це заважає оптимізатору переміщати агрегати навколо та вносити часткові агрегації. Я дуже раджу не використовувати цю підказку, за винятком дуже виняткових обставин, і справді досвідченими тюнерами.

Детальний аналіз зажадав би більше часу, ніж у мене зараз, і доступ до копії бази даних лише для статистики.


-10


Чому заперечує ліворуч Чому це ускладнює оптимізатор?
При 3-х або більше приєднаннях оптимізатор буде ТЕНДУватись оборонно і
вступати в цикл, оскільки це захищає пам'ять. А умова в об'єднанні також буде схильна переходити до циклу приєднання - чи є у мене тверді докази, що це станеться кожного разу - ні - все-таки реальність
З декількома приєднаннями витягніть умови з місця, де можна приєднатися, коли зможете

SELECT t1.id
  FROM t1
  JOIN t2 
        ON t1.id = t2.t1_id
  JOIN t3 
        ON t2.id = t3.t2_id
  JOIN t4 
        ON t3.t4_id = t4.id 
       AND t4.id = some_GUID 

Або ще краще - я думаю, що це зустріне або переможе ваші підказки чи силу

SELECT t1.id
  FROM t1
  JOIN t2 
        ON t1.id = t2.t1_id
  JOIN t3 
        ON t2.id = t3.t2_id
       AND t3.t4_id = some_GUID

Проблема з підказками полягає в тому, що вони є для даних у певному стані. Напишіть чистий запит і нехай оптимізатор виконує свою роботу. Іноді для цього потрібно просто більше статистики, щоб зробити все правильно, але тоді вона заблокується.

Чому різні оцінки. Різні плани. Почніть із запитів, що дають оптимізатору шанс на боротьбу.

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