Предложение WHERE лучше выполнять до IN и JOIN или после
Я прочитал эту статью:
Логический порядок обработки инструкции SELECT
в конце статьи было написано ON и предложение JOIN перед WHERE.
Считаем, что у нас есть мастер-таблица, в которой есть 10 milion recored и таблица подробностей (которая ссылается на главную таблицу (FK)) с записью 50 milion. У нас есть запрос, который требует всего 100 записей таблицы подробностей по PK в мастер-таблица.
В этой ситуации ON и JOIN выполняются до WHERE? Я имею в виду, что у нас есть запись 500 milion после JOIN, а затем WHERE применить к ней? или сначала WHERE применяются, а затем JOIN и ON Рассмотрим? Если второй ответ верно, некогерентность с верхней статьей?
спасибо
Ответы
Ответ 1
Не важно
Заказ логической обработки всегда соблюдается: независимо от фактического порядка обработки
Условия INNER JOIN и WHERE являются фактически ассоциативными и коммутативными (следовательно, ANSI-89 "присоединяется к синтаксису where" ), поэтому фактический порядок не имеет значения.
Логический порядок становится важным с внешними объединениями и более сложными запросами: применение WHERE в таблице OUTER полностью изменяет логику.
Опять же, неважно, как оптимизатор делает это внутри, пока семантика запроса поддерживается следующим логическим порядком обработки.
И ключевым словом здесь является "оптимизатор": он делает именно то, что он говорит
Ответ 2
В случае INNER JOIN или таблицы слева в LEFT JOIN во многих случаях оптимизатор обнаруживает, что лучше сначала выполнить какую-либо фильтрацию (максимальную избирательность) до фактического выполнения любого типа физического соединения - так что, очевидно, существует физический порядок операций.
В какой-то мере вы иногда можете контролировать это (или вмешиваться в это) со своим SQL, например, с агрегатами в подзапросах.
Логический порядок обработки ограничений в запросе может быть преобразован только в соответствии с известными инвариантными преобразованиями.
Итак:
SELECT *
FROM a
INNER JOIN b
ON a.id = b.id
WHERE a.something = something
AND b.something = something
по-прежнему логически эквивалентен:
SELECT *
FROM a
INNER JOIN b
ON a.id = b.id
AND a.something = something
AND b.something = something
и они, как правило, имеют один и тот же план выполнения.
С другой стороны:
SELECT *
FROM a
LEFT JOIN b
ON a.id = b.id
WHERE a.something = something
AND b.something = something
НЕ эквивалентен:
SELECT *
FROM a
LEFT JOIN b
ON a.id = b.id
AND a.something = something
AND b.something = something
и поэтому оптимизатор не собирается преобразовывать их в один и тот же план выполнения.
Оптимизатор очень умный и способен успешно перемещать вещи, в том числе сворачивающиеся представления и встроенные функции, ориентированные на таблицу, а также довольно быстро отбрасывая вещи через определенные типы агрегатов.
Как правило, при написании SQL он должен быть понятным, удобным и правильным. Что касается эффективности при исполнении, если оптимизатору трудно превратить декларативный SQL в план выполнения с приемлемой производительностью, иногда код может быть упрощен или соответствующие индексы или подсказки добавлены или разбиты на этапы, которые должны выполняться быстрее - все в последовательные порядки инвазивности.
Ответ 3
Просто перечитайте Paul White отличную серию в Оптимизаторе запросов и вспомнили этот вопрос.
Можно использовать недокументированную команду для отключения определенных правил преобразования и получить представление о применяемых преобразованиях.
Для (надеюсь!) очевидных причин попробуйте это только на экземпляре разработки и не забудьте снова включить их и удалить любые субоптимальные планы из кеша.
USE AdventureWorks2008;
/*Disable the rules*/
DBCC RULEOFF ('SELonJN');
DBCC RULEOFF ('BuildSpool');
SELECT P.ProductNumber,
P.ProductID,
I.Quantity
FROM Production.Product P
JOIN Production.ProductInventory I
ON I.ProductID = P.ProductID
WHERE I.ProductID < 3
OPTION (RECOMPILE)
Вы можете видеть, что эти два правила отключены, после чего происходит декартовое объединение и фильтр.
![Rules Off Plan]()
/*Re-enable them*/
DBCC RULEON ('SELonJN');
DBCC RULEON ('BuildSpool');
SELECT P.ProductNumber,
P.ProductID,
I.Quantity
FROM Production.Product P
JOIN Production.ProductInventory I
ON I.ProductID = P.ProductID
WHERE I.ProductID < 3
OPTION (RECOMPILE)
С их помощью предикат подталкивается прямо в индексный поиск и таким образом уменьшает количество строк, обработанных операцией join.
![Rules on Plan]()
Ответ 4
Нет определенного порядка. Механизм SQL определяет, какой порядок выполнения операций основан на стратегии выполнения, выбранной его оптимизатором.
Ответ 5
Я думаю, что вы неправильно поняли ON
как IN
в этой статье.
Однако порядок, который он показывает в статье, является правильным (очевидно, это msdn). ON
и JOIN
выполняются до WHERE
естественным образом, потому что WHERE
должен применяться как фильтр на временном результирующем наборе, полученном из-за JOINS
В статье говорится, что это логический порядок выполнения, а также в конце абзаца он также добавляет эту строку;)
"Обратите внимание, что фактическое физическое выполнение оператора определяется процессором запросов, и порядок может отличаться от этого списка."