Почему оценки строк SQL Server меняются, когда я добавляю подсказку о соединении?


15

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

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

Играя с запросом, я заметил, что когда я намекаю на использование объединения слиянием для одного из объединений, он выполняется во много раз быстрее. Это я могу понять - объединение слиянием - лучший вариант для объединенных данных, но SQL Server просто не оценивает правильность выбора вложенных циклов.

Что я не до конца понимаю, так это то, почему этот намек на объединение меняет все оценки для всех операторов плана? Из прочтения различных статей и книг я предположил, что оценки количества элементов выполняются до того, как составлен план, поэтому использование подсказки не изменило бы оценки, а скорее явно указало бы SQL Server использовать конкретную реализацию физического объединения.

Однако я вижу, что подсказка Merge делает все оценки в значительной степени идеальными. Почему это происходит, и существуют ли какие-либо распространенные методы, позволяющие оптимизатору запросов делать более точную оценку без намеков - учитывая, что статистика, очевидно, учитывает это?

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
Вы заметили, что у вас есть внешнее соединение, но вы используете таблицу в предложении where?
Джеймс З,

@JamesZ - да, я знаю об этом, но не думаю, что с этим есть проблема.
Александр Шелемин

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

Ответы:


21

Из прочтения различных статей и книг я предположил, что оценки мощности выполняются до составления плана.

Не совсем. Получается начальная оценка количества элементов (после упрощений и другой работы), которая влияет на начальный порядок соединения, выбранный оптимизатором.

Однако последующие исследования (во время оптимизации на основе затрат) могут и часто приводят к вычислению новых оценок мощности. Эти более поздние CE могут быть более или менее «точными». Если результаты занижены, оптимизатор может выбрать план, который выглядит дешевле, но на самом деле работает гораздо дольше.

В общем, нет никакой гарантии, что оценки мощности для семантически идентичных поддеревьев дадут одинаковые результаты. В конце концов, это статистический процесс, и некоторые операции имеют более глубокую поддержку CE, чем другие.

В вашем случае, похоже, есть еще один фактор - оптимизатор вводит (или перемещает) вершину, которая устанавливает цель строки для поддерева под ним:

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

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

Однако я вижу, что подсказка Merge делает все оценки в значительной степени идеальными.

Здесь есть элемент удачи. Люди обычно пишут запросы или, по крайней мере, объединения, в том порядке, в котором они ожидают, что они будут выполнены физически. Использование подсказки о соединении подразумевает подразумеваемое 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.