выбор оператора оптимизатора запросов - вложенные циклы или совпадение хешей - PullRequest
20 голосов
/ 11 декабря 2011

Одна из моих хранимых процедур выполнялась слишком долго. Взглянув на план выполнения запроса, я смог найти операцию, которая заняла слишком много времени. Это был физический оператор с вложенным циклом, который имел внешнюю таблицу (65991 строк) и внутреннюю таблицу (19223 строки). На вложенном цикле он показал приблизительные строки = 1 268 544 993 (умножив 65991 на 19223), как показано ниже:

enter image description here

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

Hash Match - используется оптимизатором, когда нет доступных полезных индексов, одна таблица существенно меньше другой, таблицы не сортируются по столбцам соединения. Также совпадение хеша может указывать на более эффективный метод соединения (вложенные циклы или объединение слиянием).

Вопрос: Будет ли совпадение хеша лучше, чем вложенные циклы в этом сценарии?

Спасибо

Ответы [ 2 ]

25 голосов
/ 06 февраля 2012

АБСОЛЮТНО.Хеш-матч был бы огромным улучшением.Создание хеша для таблицы строк меньшего размера 19 223, а затем поиск в ней с помощью таблицы строк большего размера, равной 65 991, является гораздо меньшей операцией, чем для вложенного цикла, требующего 1 268 544 993 сравнения строк.

Единственная причина, по которой сервер выбирает вложенные циклы, заключается в том, чточто он сильно недооценил количество задействованных строк.Есть ли в ваших таблицах статистика по ним, и если да, регулярно ли они обновляются?Статистика - это то, что позволяет серверу выбирать хорошие планы выполнения.

Если вы правильно обращались к статистике и у вас все еще есть проблема, вы можете заставить ее использовать HASH-соединение следующим образом:

SELECT *
FROM
   TableA A -- The smaller table
   LEFT HASH JOIN TableB B -- the larger table

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

Как правило, лучше избегать использования подсказок о соединении и принудительного порядка соединения, поэтому сначала делайте все, что можете!Вы можете посмотреть на индексы в таблицах, фрагментацию, уменьшить размеры столбцов (например, использовать varchar вместо nvarchar, где Unicode не требуется) или разбить запрос на части (сначала вставьте во временную таблицу, а затем соединитек этому).

10 голосов
/ 10 февраля 2012

Я бы не рекомендовал пытаться «исправить» план, заставляя подсказки в ту или иную сторону.Вместо этого вам нужно взглянуть на свои индексы, статистику и код TSQL, чтобы понять, почему у вас есть спул Table, загружающий 1,2 миллиарда строк из 19000.

...