Хэш-соединения SQL Server против вложенных циклов
Быстрая заметка
Итак, когда я писал проблему ниже, я нашел способ решить ее самостоятельно. Я думал, что все еще отправлю вопрос, потому что:
- Кто-то может найти это полезным.
- Я не очень понимаю, почему это работает.
В любом случае фиксированный код (см. Ответы).
Я изначально написал:
Я целую вечность гуглял по этому вопросу и могу найти много похожих ответов, но ни один из них не соответствует моему вопросу.
Я запускаю приведенный ниже код для базы данных SQL Server (10), и он выполняется очень быстро. План выполнения, который он использует, включает хеш-соединение.
Затем я запускаю его снова, но на этот раз раскомментируйте первые две строки (DECLARE и SET), а также удалите "+1" рядом с y.[В дате] и раскомментируйте "+ @COUNTER". Теперь для выполнения запроса требуются возрасты (по возрастам) - вместо этого используется план выполнения с использованием вложенных циклов. Обратите внимание, я все еще просто добавляю один к дате, но использую переменную вместо константы.
Вопрос в том, могу ли я сделать запрос, используя @COUNTER, использовать хеш-соединение вместо вложенного цикла?
(Немного предыстории: то, что я пытаюсь сделать, это слабое совпадение x.[В дате] и y.[В дате], чтобы они совпадали, если они находятся в пределах определенного количества дней друг от друга. Число дни, в которых используется запрос, заполняется из поля в другой таблице. Сначала я попытался использовать datediff() с abs() и less, но я почти уверен, что всегда будут использоваться вложенные циклы. это все равно!)
Я пытался делать все, что упоминалось в различных статьях по анализу параметров, но они ничего не изменили. Во всяком случае, я не запускаю это как хранимую процедуру. Я предполагаю, что есть какое-то отношение к индексу в поле [в дате].)
-- DECLARE @COUNTER INT
-- SET @COUNTER = 1
BEGIN
SELECT
x.[line id]
, y.[line id]
FROM
lines1 AS x
JOIN lines2 AS y ON (
x.[in date] = y.[in date] + 1 -- + @COUNTER
AND x.[country] = y.[country]
)
WHERE
x.[country] = 'USA'
END
1 ответ
Вопрос в том, могу ли я сделать запрос, используя @COUNTER, использовать хеш-соединение вместо вложенного цикла?
Да. Вы можете использовать подсказку соединения, чтобы форсировать это:
INNER HASH JOIN
Вот фиксированный код:
WITH test_tbl AS (
SELECT -1 AS [col]
UNION ALL
SELECT 0 AS [col]
UNION ALL
SELECT 1 AS [col]
)
SELECT
x.[line id]
, y.[line id]
FROM
lines1 AS x
CROSS JOIN test_tbl AS z
JOIN lines2 AS y ON (
x.[in date] = y.[in date] + z.[col]
AND x.[country] = y.[country]
)
WHERE
x.[country] = 'USA'
Очевидно, мне придется выяснить, как заполнить временную таблицу на лету, вместо того, чтобы использовать WITH и UNION ALL. Я не эксперт по SQL Server (очевидно), но это не должно быть слишком сложно.