INNER JOIN ON vs WHERE предложение

для простоты предположим, что все соответствующие поля NOT NULL.

вы можете сделать:

SELECT
    table1.this, table2.that, table2.somethingelse
FROM
    table1, table2
WHERE
    table1.foreignkey = table2.primarykey
    AND (some other conditions)

или еще:

SELECT
    table1.this, table2.that, table2.somethingelse
FROM
    table1 INNER JOIN table2
    ON table1.foreignkey = table2.primarykey
WHERE
    (some other conditions)

эти два работают одинаково в MySQL?

10 ответов


INNER JOIN - синтаксис ANSI, который вы должны использовать.

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

его также можно легко заменить на OUTER JOIN всякий раз, когда потребность возникает.

на WHERE синтаксис больше ориентирован на реляционную модель.

результат двух таблиц JOINЭД является декартовым произведением таблиц, к которым применяется фильтр, который выбирает только те строки, соединяя столбцы совмещение.

легче увидеть это с помощью тега WHERE синтаксис.

Что касается вашего примера, в MySQL (и в SQL вообще) эти два запроса являются синонимами.

Также обратите внимание, что MySQL также имеет STRAIGHT_JOIN предложения.

используя это предложение, вы можете управлять JOIN order: какая таблица сканируется во внешнем цикле и какая находится во внутреннем цикле.

вы не можете контролировать это в MySQL, используя WHERE синтаксис.


другие указали, что внутреннее соединение помогает читаемости человека, и это главный приоритет; я согласен. Позвольте мне попытаться объяснить почему синтаксис соединения более удобочитаем.

основной запрос выбора таков:

SELECT stuff
FROM tables
WHERE conditions

предложение SELECT сообщает нам что мы возвращаемся; предложение FROM говорит нам здесь мы получаем его, и предложение WHERE говорит нам , который те, которые мы получаем.

JOIN является утверждение о таблицах, как они связаны друг с другом (концептуально, фактически, в одну таблицу). Любые элементы запроса, которые управляют таблицами-откуда мы получаем материал-семантически принадлежат предложению FROM (и, конечно, именно туда идут элементы JOIN). Включение элементов-соединений в предложение WHERE объединяет , который и где-с; поэтому синтаксис Join предпочтительнее.


применение условных операторов в ON / WHERE

здесь я объяснил о логических шагах обработки запросов.


ссылка: внутри Microsoft® SQL Server™ 2005 T-SQL запрос
Издатель: Microsoft Press
Дата Публикации: 07 Марта 2006
Print ISBN-10: 0-7356-2313-9
Print ISBN-13: 978-0-7356-2313-2
Страниц: 640

внутри Microsoft® SQL Server™ 2005 T-SQL Запрос

(8)  SELECT (9) DISTINCT (11) TOP <top_specification> <select_list>
(1)  FROM <left_table>
(3)       <join_type> JOIN <right_table>
(2)       ON <join_condition>
(4)  WHERE <where_condition>
(5)  GROUP BY <group_by_list>
(6)  WITH {CUBE | ROLLUP}
(7)  HAVING <having_condition>
(10) ORDER BY <order_by_list>

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

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

краткое описание этапов обработки логических запросов

Не волнуйтесь слишком много, если описание шагов, похоже, не имеет большого смысла на данный момент. Они приводятся в качестве справочного материала. Разделы, которые приходят после того, как пример сценария будет охватывать шаги гораздо более подробно.

  1. FROM: Декартовое произведение (перекрестное соединение) выполняется между первыми двумя таблицами в предложении FROM, и в результате создается виртуальная таблица VT1.

  2. ON: фильтр ON применяется к VT1. Только строки, для которых <join_condition> is TRUE вставляются в VT2.

  3. OUTER (join): если указано внешнее соединение (в отличие от перекрестного соединения или внутреннее соединение), строки из сохраненной таблицы или таблицы, для которых совпадение не найдено, добавляются в строки из VT2 как внешние строки, генерирующие VT3. Если в предложении FROM появляется более двух таблиц, шаги с 1 по 3 применяются повторно между результатом последнего соединения и следующей таблицей в предложении FROM, пока не будут обработаны все таблицы.

  4. WHERE: фильтр WHERE применяется к VT3. Только строки, для которых <where_condition> is TRUE вставляются в VT4 по.

  5. GROUP BY: строки из VT4 расположены в группах на основе списка столбцов, указанного в предложении GROUP BY. ВТ5 генерируется.

  6. CUBE / ROLLUP: супергруппы (группы групп) добавляются в строки из VT5, генерируя VT6.

  7. наличие: фильтр наличия применяется к VT6. Только группы, для которых <having_condition> TRUE вставляются в VT7.

  8. SELECT: список выбора обработано, генерируя VT8.

  9. DISTINCT: повторяющиеся строки удаляются из VT8. VT9 генерируется.

  10. ORDER BY: строки из VT9 сортируются в соответствии со списком столбцов, указанным в предложении ORDER BY. Создается курсор (VC10).

  11. TOP: указанное количество или процент строк выбирается с начала VC10. Таблица VT11 создается и возвращается абонент.



Поэтому (внутреннее соединение) ON будет фильтровать данные (количество данных VT будет уменьшено здесь) перед применением предложения WHERE. Последующие условия соединения будут выполняться с отфильтрованными данными, что повышает производительность. После этого только условие WHERE будет применять условия фильтра.

(применение условных операторов в ON / WHERE не будет иметь большого значения в нескольких случаях. Это зависит от того, сколько таблиц вы присоединились и количество строк, доступных в каждой таблице соединения)


неявный синтаксис соединения ANSI старше, менее очевиден и не рекомендуется.

кроме того, реляционная алгебра позволяет взаимозаменяемость предикатов в WHERE п. и INNER JOIN, да еще INNER JOIN запрос WHERE пункты могут иметь предикаты rearrranged оптимизатором.

я рекомендую вам писать запросы в наиболее readble возможным способом.

иногда это включает в себя создание 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

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


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

использование явного соединения (ваш второй пример) гораздо более читабельно и легко поддерживать.


Я также отмечу, что использование старого синтаксиса больше подвержено ошибкам. Если вы используете внутренние соединения без предложения ON, вы получите синтаксическую ошибку. Если вы используете старый синтаксис и забыли одно из условий соединения в предложении where, вы получите перекрестное соединение. Разработчики часто исправляют это, добавляя ключевое слово distinct (а не фиксируя соединение, потому что они все еще не понимают, что само соединение сломано), которое может показаться, чтобы устранить проблему, но замедлит запрос значительно.

дополнительно для обслуживания если у вас есть перекрестное соединение в старом синтаксисе, как будет сопровождающий знать, если вы хотели бы иметь один (есть ситуации, когда перекрестные соединения необходимы) или если это был несчастный случай, который должен быть исправлен?

позвольте мне указать вам на этот вопрос, чтобы понять, почему неявный синтаксис плох, если вы используете левые соединения. Sybase * = к стандарту Ansi с 2 различными наружными таблицами для такой же внутренней таблицы

плюс (личным rant здесь), стандарт, использующий явные соединения, старше 20 лет, что означает, что неявный синтаксис соединения устарел за эти 20 лет. Вы бы написали код приложения, используя синтаксис, который устарел за 20 лет? Почему вы хотите написать код базы данных?


Они имеют другое человекочитаемое значение.

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

вы всегда должны код для чтения.

то есть, если это встроенное отношение, используйте явное соединение. если вы сопоставляете слабо связанные данные, используйте предложение where.


стандарт SQL:2003 изменил некоторые правила приоритета, поэтому оператор JOIN имеет приоритет над соединением "запятая". Это действительно может изменить результаты вашего запроса в зависимости от способа установки. Это вызывает некоторые проблемы для некоторых людей, когда MySQL 5.0.12 переключился на соблюдение стандарта.

таким образом, в вашем примере ваши запросы будут работать одинаково. Но если вы добавили третью таблицу: ВЫБИРАТЬ... От table1, table2 присоединиться table3 на ... ГДЕ...

до MySQL 5.0.12, table1 и table2 будут объединены сначала, затем table3. Теперь (5.0.12 и далее), table2 и table3 соединяются сначала, затем table1. Это не всегда меняет результаты, но это может, и вы даже не поймете этого.

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


Я знаю, что вы говорите о MySQL, но в любом случае: В Oracle 9 явные и неявные соединения будут генерировать разные планы выполнения. AFAIK, который был решен в Oracle 10+: больше нет такой разницы.


синтаксис ANSI join определенно более переносим.

Я прохожу обновление Microsoft SQL Server, и я бы также упомянул, что синтаксис =* и *= для внешних соединений в SQL Server не поддерживается (без режима совместимости) для 2005 sql server и более поздних версий.