Хэш-соединения SQL Server против вложенных циклов


Быстрая заметка

Итак, когда я писал проблему ниже, я нашел способ решить ее самостоятельно. Я думал, что все еще отправлю вопрос, потому что:

  1. Кто-то может найти это полезным.
  2. Я не очень понимаю, почему это работает.

В любом случае фиксированный код (см. Ответы).


Я изначально написал:

Я целую вечность гуглял по этому вопросу и могу найти много похожих ответов, но ни один из них не соответствует моему вопросу.

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

Другие вопросы по тегам