Состояние в рамках СОЗДАНИЯ или ГДЕ

Есть ли разница (производительность, передовая практика и т.д.) между помещением условия в предложение JOIN и предложение WHERE?

Например...

-- Condition in JOIN
SELECT *
FROM dbo.Customers AS CUS
INNER JOIN dbo.Orders AS ORD 
ON CUS.CustomerID = ORD.CustomerID
AND CUS.FirstName = 'John'

-- Condition in WHERE
SELECT *
FROM dbo.Customers AS CUS
INNER JOIN dbo.Orders AS ORD 
ON CUS.CustomerID = ORD.CustomerID
WHERE CUS.FirstName = 'John'

Что вы предпочитаете (и, возможно, почему)?

Ответ 1

Реляционная алгебра обеспечивает взаимозаменяемость предикатов в WHERE и INNER JOIN, поэтому даже в запросах INNER JOIN с WHERE предикаты могут быть переупорядочены оптимизатором, так что они могут быть уже исключены во время процесса JOIN.

Я рекомендую вам писать запросы в максимально удобочитаемой форме.

Иногда это включает в себя создание INNER JOIN относительно "неполным" и помещение некоторых критериев в WHERE чтобы сделать списки критериев фильтрации более легкими в обслуживании.

Например, вместо:

SELECT *
FROM Customers c
INNER JOIN CustomerAccounts ca
    ON ca.CustomerID = c.CustomerID
    AND c.State = 'NY'
INNER JOIN Accounts a
    ON ca.AccountID = a.AccountID
    AND a.Status = 1

Написать:

SELECT *
FROM Customers c
INNER JOIN CustomerAccounts ca
    ON ca.CustomerID = c.CustomerID
INNER JOIN Accounts a
    ON ca.AccountID = a.AccountID
WHERE c.State = 'NY'
    AND a.Status = 1

Но это зависит, конечно.

Ответ 2

Для внутренних объединений я действительно не заметил разницы (но, как и во всех настройках производительности, вам необходимо проверить свою базу данных в ваших условиях).

Однако, когда вы ставите условие, это имеет огромное значение, если вы используете левое или правое соединение. Например, рассмотрите эти два запроса:

SELECT *
FROM dbo.Customers AS CUS 
LEFT JOIN dbo.Orders AS ORD 
ON CUS.CustomerID = ORD.CustomerID
WHERE ORD.OrderDate >'20090515'

SELECT *
FROM dbo.Customers AS CUS 
LEFT JOIN dbo.Orders AS ORD 
ON CUS.CustomerID = ORD.CustomerID
AND ORD.OrderDate >'20090515'

Первый даст вам только те записи, которые имеют заказ от 15 мая 2009 года, таким образом преобразовывая левое соединение во внутреннее соединение. Второй даст эти записи плюс любые клиенты без заказов. Набор результатов очень отличается в зависимости от того, где вы положили условие. (Выберите *, если, например, только для целей, вы не должны использовать, конечно, производственный код.) Исключением является то, что вы хотите видеть только записи в одной таблице, а не другую. Затем вы используете предложение where для условия, а не соединения.

SELECT *
FROM dbo.Customers AS CUS 
LEFT JOIN dbo.Orders AS ORD 
ON CUS.CustomerID = ORD.CustomerID
WHERE ORD.OrderID is null

Ответ 3

Большинство продуктов RDBMS будут одинаково оптимизировать оба запроса. В "SQL Performance Tuning" Питера Гулуцана и Труди Пельцер они протестировали несколько брендов РСУБД и не обнаружили разницы в производительности.

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

Если вы используете OUTER JOIN, иногда необходимо поставить условия в предложение соединения.

Ответ 4

WHERE будет фильтроваться после того, как произошел JOIN.

Фильтр в JOIN для предотвращения добавления строк во время процесса JOIN.

Ответ 5

Я предпочитаю, чтобы JOIN присоединился к полным таблицам/представлениям, а затем использовал WHERE Чтобы ввести предикат результирующего набора.

Он чувствует себя синтаксически чистым.

Ответ 6

Обычно я вижу увеличение производительности при фильтрации по соединению. Особенно, если вы можете присоединиться к индексированным столбцам для обеих таблиц. Вы должны иметь возможность обрезать логические чтения с помощью большинства запросов, которые тоже делают это в среде с большими объемами намного лучше, чем время выполнения.

Я всегда слегка удивляюсь, когда кто-то показывает их бенчмаркинг SQL, и они выполнили обе версии sproc 50 000 раз в полночь на сервере dev и сравнили среднее время.

Ответ 7

Полагая условие в соединении кажется мне "семантически неправильным", поскольку это не то, что JOINs "для". Но это очень качественное.

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

Ответ 8

Соединения быстрее, на мой взгляд, когда у вас большой стол. Это действительно не такая уж большая разница, особенно если вы имеете дело с довольно маленькой таблицей. Когда я впервые узнал о объединениях, мне сказали, что условия в соединениях аналогичны условиям условий предложения и что я могу использовать их взаимозаменяемо, если предложение where было специфическим для какой таблицы выполнить условие.

Ответ 9

Лучше добавить условие в Join. Производительность важнее, чем удобочитаемость. Для больших наборов данных это имеет значение.