ВНУТРЕННЕЕ ПРИСОЕДИНЕНИЕ НА ПУТЬ К ГДЕ - PullRequest
858 голосов
/ 19 июня 2009

Для простоты предположим, что все соответствующие поля 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 ]

660 голосов
/ 19 июня 2009

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

Обычно считается более читабельным, особенно когда вы объединяете множество таблиц.

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

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

Результат двух таблиц JOIN ed - это декартово произведение таблиц, к которым применен фильтр, который выбирает только те строки с совпадающими столбцами.

Это проще увидеть с помощью синтаксиса WHERE.

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

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

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

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

164 голосов
/ 19 июня 2009

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

Основной запрос SELECT выглядит так:

SELECT stuff
FROM tables
WHERE conditions

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

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

126 голосов
/ 22 декабря 2009

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

Здесь я объяснил этапы обработки логического запроса.


Ссылка: Внутри Microsoft® SQL Server ™ 2005 T-SQL-запросов
Издатель: Microsoft Press
Дата публикации: 7 марта 2006 г.
Печать ISBN-10: 0-7356-2313-9
Печать 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, и в результате создается виртуальная таблица VT1.

  2. ON: Фильтр ON применяется к VT1. В VT2 вставляются только те строки, для которых <join_condition> - ИСТИНА.

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

  4. ГДЕ: ГДЕ фильтр применяется к VT3. В VT4 вставляются только те строки, для которых <where_condition> - ИСТИНА.

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

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

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

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

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

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

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



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

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

60 голосов
/ 19 июня 2009

Синтаксис неявного объединения ANSI более старый, менее очевидный и не рекомендуется.

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

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

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

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

29 голосов
/ 19 июня 2009

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

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

25 голосов
/ 19 июня 2009

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

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

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

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

12 голосов
/ 19 июня 2009

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

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

Вы всегда должны кодировать, чтобы быть читаемым.

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

11 голосов
/ 19 июня 2009

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

Так что в вашем примере ваши запросы будут работать одинаково. Но если вы добавили третью таблицу: SELECT ... FROM table1, table2 ПРИСОЕДИНЯЙТЕСЬ к table3 ON ... WHERE ...

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

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

4 голосов
/ 19 июня 2009

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

1 голос
/ 19 июня 2009

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

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

...