почему SQL Server делает вложенные циклы - PullRequest
0 голосов
/ 04 октября 2018

У меня есть 2 таблицы фактов и клиент, с 422 000 и 350 000 строк.

При выполнении этого запроса используется соединение по хэшу:

SELECT SUM(sales), [state], County
FROM pp.Facts f
INNER JOIN pp.Customer c ON (c.customerKey = f.customerKey)
WHERE c.County IN (N'Nassau', N'Westchester', N'Erie', N'Orange', N'Union', 
                   N'Santa Clara', N'San Diego', N'Essex', N'Morris', 
                   N'Dallas', N'Allegheny', N'Bucks')
GROUP BY [state], County

И оно прекрасно работает.

Когда выполняется запрос (тот же, но с большим количеством элементов в фильтре), объединение изменяется на «Вложенные циклы» и никогда не возвращается (очевидно)

SELECT SUM(sales), [state], County
FROM pp.Facts f
INNER JOIN pp.Customer c ON (c.customerKey = f.customerKey)
WHERE c.County IN (N'Nassau', N'Westchester', N'Erie', N'Orange', N'Union', 
                   N'Santa Clara', N'San Diego', N'Essex', N'Morris', 
                   N'Dallas', N'Allegheny', N'Bucks', N'New York', 
                   N'Bergen', N'Montgomery', N'Harris', N'Delaware', N'San 
                   Francisco', N'Suffolk', N'Travis', N'Middlesex', 
                   N'Bexar', N'Tarrant', N'Los Angeles', N'Philadelphia')
GROUP BY [state], County

Почему метод объединения изменился?

В столбцах customerKey определены FK, а в customer.customerKey - PK (без дополнительных индексов)

Ответы [ 2 ]

0 голосов
/ 04 октября 2018

SQL Server выбирает план с точки зрения ресурсов.Тип соединения (LOOP | MERGE | HASH) выбирается исходя из предполагаемого количества строк и порядка.Если у вас нет индексов, dbms может быть плохим при вычислении результата строк и, при «большем» количестве условий, принять гораздо меньшее количество строк и, как следствие, построить план с NL.Попробуйте создать статистику по индексу (customerKey, Country), NC.Или используйте подсказки INNER HASH JOIN или весь запрос OPTION (HASH JOIN).Но если условия изменятся, вы можете получить плохой план, используя подсказки.

0 голосов
/ 04 октября 2018

Почему?Это просто.Когда SQL Server анализирует запрос на этапе компиляции, оптимизатор рассматривает разные планы выполнения.Очевидно, оптимизатор считает, что вложенный цикл более эффективен, чем другие методы.

Оптимизатор неверен, возможно, из-за неправильной статистики или из-за того, что предположения о распределении значений неверны для вашего запроса.

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

OPTION (HASH JOIN)

Для этого запроса:

SELECT SUM(f.sales), c.[state], c.County
FROM pp.Facts f INNER JOIN
     pp.Customer c
     ON c.customerKey = f.customerKey
WHERE c.County IN ( . . . )
GROUP BY c.[state], c.County;

Требуются индексы для Customer(County, State, CustomerKey) и Facts(customerKey, sales).Индекс является индексом покрытия.Первый столбец должен удовлетворять условию WHERE.

Я заметил, что вы используете nvarchar константы.Это предполагает, что c.County равно nvarchar.Если это varchar, сбросьте N.

...