it-roy-ru.com

ВНУТРЕННЕЕ ПРИСОЕДИНЕНИЕ НА ПУТЬ К ГДЕ

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

856
JCCyC

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

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

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

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

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

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

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

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

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

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

657
Quassnoi

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

Основной запрос SELECT:

SELECT stuff
FROM tables
WHERE conditions

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

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

164
Carl Manaster

Применение условных операторов в 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> равен TRUE.

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

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

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

  6. КУБ | 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 генерируется и возвращается вызывающей стороне.



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

126
rafidheen

Синтаксис неявного соединения 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

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

60
Cade Roux

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

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

29
matt b

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

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

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

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

25
HLGEM

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

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

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

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

12
John Gietzen

Стандарт 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, а не разделены на отдельный раздел запроса.

11
Brent Baisley

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

4
João Marcus

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

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

1
Benzo