Ваш первый вариант с явным объединением двух таблиц в явных полях - лучший выбор по ряду причин.
Второй вариант по-прежнему является эффективным объединением, даже если вы не используете ключевое слово JOIN, поскольку оно подразумевает подразумеваемое объединение. Это означает, что ваш движок базы данных будет эффективно выполнять собственное соединение между списком таблиц.
В MySQL это подразумеваемое соединение является CROSS JOIN, которое в MySQL эквивалентно INNER JOIN, однако следует помнить, что CROSS JOIN НЕ эквивалентно INNER JOIN в «стандартном» SQL, поэтому ваш второй запрос может хорошо работает, если построено правильно с правильной фильтрацией, это неоднозначно.
В результате, ваш второй запрос (с подразумеваемым соединением) может эффективно создать декартово произведение между двумя таблицами (где фактически каждая строка из одной таблицы объединяется с каждой строкой из другой таблицы). Вы почти наверняка НЕ захотите этого, и это один из способов снизить производительность SQL-запроса, особенно если хотя бы одна из таблиц содержит довольно много строк! Даже если ваши предложения фильтра (т.е. ваши предложения WHERE) могут правильно отфильтровывать строки, которые вы не хотите возвращать только правильный набор результатов, это будет менее эффективно, чем явное определение ваших собственных явных объединений (даже если большинство механизмов баз данных будут попытка оптимизировать такие подразумеваемые запросы). Ваш первый запрос использует явное LEFT JOIN, и поэтому декартово произведение не должно быть возможным (при условии, что вы соединяетесь с «разумными» полями - из вашего вопроса кажется, что табличное отношение «разумное»).
Также следует помнить, что приоритет простого указания объединений между таблицами путем перечисления таблиц с разделителем-запятой ниже, чем фактические явные операторы JOIN (по крайней мере, начиная с MySQL v5.x). Это может привести к неверным результатам запроса, особенно в случай объединения трех или более таблиц, где неоднозначность в выражении запроса также затрудняет определение приоритета, и, следовательно, один и тот же запрос может давать совершенно разные результаты в разных версиях базы данных. См. эту ссылку для получения дополнительной информации.
Лучшим источником информации для различных типов JOIN в MySQL является сама документация MySQL, а страницу, относящуюся к соединениям, можно найти здесь:
12.2.8.1. Синтаксис JOIN (MySql v5)
12.2.9.1. Синтаксис JOIN (MySql v6)
Только для скорости, я процитировал наиболее подходящие разделы ниже:
INNER JOIN и (запятая) семантически эквивалентны в отсутствие условия соединения: оба производят декартово произведение между указанными таблицами (то есть каждая строка в первой таблице объединяется с каждой строкой в вторая таблица).
Однако приоритет оператора запятой меньше, чем у INNER JOIN, CROSS JOIN, LEFT JOIN и т. Д. Если вы смешиваете запятые объединения с другими типами соединений, когда существует условие соединения, может произойти ошибка формы Неизвестный столбец «col_name» в «условии».
-
Оценка многомерных естественных объединений отличается очень важным способом, который влияет на результат соединений NATURAL или USING и может потребовать переписывания запросов. Предположим, что у вас есть три таблицы t1 (a, b), t2 (c, b) и t3 (a, c), каждая из которых имеет одну строку: t1 (1,2), t2 (10,2) и t3 ( 7,10). Предположим также, что у вас есть это ЕСТЕСТВЕННОЕ СОЕДИНЕНИЕ на трех таблицах:
ВЫБРАТЬ ... ИЗ t1 ЕСТЕСТВЕННОЕ СОЕДИНЕНИЕ t2 ЕСТЕСТВЕННОЕ СОЕДИНЕНИЕ t3;
Ранее левый операнд второго соединения считался t2, тогда как это должно быть вложенное соединение (t1 NATURAL JOIN t2). В результате столбцы t3 проверяются на наличие общих столбцов только в t2, и, если t3 имеет общие столбцы с t1, эти столбцы не используются в качестве столбцов равного соединения. Таким образом, ранее предыдущий запрос был преобразован в следующее уравнение:
ВЫБРАТЬ ... ОТ t1, t2, t3ГДЕ t1.b = t2.b И t2.c = t3.c;
В этом соединении отсутствует еще один предикат равного соединения (t1.a = t3.a). В результате он выдает одну строку, а не пустой результат, который должен. Правильный эквивалентный запрос:
ВЫБРАТЬ ... ОТ t1, t2, t3
ГДЕ t1.b = t2.b И t2.c = t3.c И t1.a = t3.a;
Если вам требуется тот же результат запроса в текущих версиях MySQL, что и в более старых версиях, перепишите естественное соединение в качестве первого равного соединения.
-
Ранее оператор запятой (,) и JOIN имели одинаковый приоритет, поэтому выражение соединения t1, t2 JOIN t3 интерпретировалось как ((t1, t2) JOIN t3). Теперь JOIN имеет более высокий приоритет, поэтому выражение интерпретируется как (t1, (t2 JOIN t3)). Это изменение влияет на операторы, использующие предложение ON, потому что это предложение может ссылаться только на столбцы в операндах соединения, а изменение в приоритете меняет интерпретацию того, чем являются эти операнды.
Пример:
CREATE TABLE t1 (i1 INT, j1 INT);
CREATE TABLE t2 (i2 INT, j2 INT);
CREATE TABLE t3 (i3 INT, j3 INT);
ВСТАВЬТЕ В ЗНАЧЕНИЯ t1 (1,1);
INSERT INTO t2 VALUES (1,1);
INSERT INTO T3 VALUES (1,1);
ВЫБРАТЬ * ОТ t1, t2 ПРИСОЕДИНИТЬСЯ к t3 ВКЛ (t1.i1 = t3.i3);
Ранее SELECT был допустимым из-за неявной группировки t1, t2 как (t1, t2). Теперь JOIN имеет приоритет, поэтому операндами для предложения ON являются t2 и t3. Поскольку t1.i1 не является столбцом ни в одном из операндов, результатом будет ошибка Unknown column 't1.i1' в 'on clause'. Чтобы разрешить обработку объединения, сгруппируйте первые две таблицы явно в круглых скобках, чтобы операндами для предложения ON были (t1, t2) и t3:
ВЫБРАТЬ * ИЗ (t1, t2) ПРИСОЕДИНИТЬСЯ t3 ВКЛ (t1.i1 = t3.i3);
В качестве альтернативы, избегайте использования оператора запятой и используйте вместо этого JOIN:
ВЫБРАТЬ * ОТ t1 ПРИСОЕДИНИТЬСЯ t2 ПРИСОЕДИНИТЬСЯ t3 ВКЛ (t1.i1 = t3.i3);
Это изменение также применяется к операторам, которые смешивают оператор запятой с INNER JOIN, CROSS JOIN, LEFT JOIN и RIGHT JOIN, и все они теперь имеют более высокий приоритет, чем оператор запятой.