Hash Join обычно (всегда?) Использует сканирование или, по крайней мере, сканирование диапазона. Хеш-соединение работает путем сканирования как левой, так и правой таблиц соединения (или диапазона в таблицах) и построения хеш-таблицы в памяти, которая содержит все значения, «видимые» при сканировании.
В вашем случае произошло следующее: QO заметил, что он может получить все значения столбца C из некластеризованного индекса, который содержит этот столбец (как ключ или как включенный столбец). Быть некластеризованным индексом, вероятно, довольно узко, поэтому общий объем операций ввода-вывода для сканирования всего некластеризованного индекса не является преувеличенным. QO также считает, что в системе достаточно оперативной памяти для хранения хеш-таблицы в памяти. При сравнении стоимости этого запроса (сканирование сквозного некластеризованного индекса, скажем, для 10000 страниц) со стоимостью вложенного цикла, который использовал поиск (скажем, 5000 тестов по 2-3 страницы каждый), сканирование выиграл как требующий меньше IO. Конечно, во многом это спекуляция с моей стороны, но я пытаюсь представить случай с точки зрения QO, и план, вероятно, является оптимальным.
Факторы, повлиявшие на выбор данного плана:
- большое количество предполагаемых кандидатов на правой стороне объединения
- доступность столбца соединения в узком некластеризованном индексе для левой стороны
- много оперативной памяти
Для большой оценки числа кандидатов лучшим выбором, чем хеш-соединение, является только соединение слиянием, и для этого требуется предварительная сортировка ввода. Если и левая сторона может предложить путь доступа, который гарантирует порядок в объединенном столбце, а правая сторона имеет аналогичную возможность, то вы можете получить объединение слиянием, которое является самым быстрым соединением.