Левое соединение или выбор из нескольких таблиц с помощью запятой (,) [дубликат]
На этот вопрос уже есть ответ здесь:
Мне любопытно, почему мы должны использоватьLEFT JOIN
, поскольку мы можем использовать запятые для выбора нескольких таблиц.
В чем разница между LEFT JOIN
и использованием запятых для выбора нескольких таблиц.
Который из них быстрее?
Вот мой код:
SELECT mw.*,
nvs.*
FROM mst_words mw
LEFT JOIN (SELECT no as nonvs,
owner,
owner_no,
vocab_no,
correct
FROM vocab_stats
WHERE owner = 1111) AS nvs ON mw.no = nvs.vocab_no
WHERE (nvs.correct > 0 )
AND mw.level = 1
...и:
SELECT *
FROM vocab_stats vs,
mst_words mw
WHERE mw.no = vs.vocab_no
AND vs.correct > 0
AND mw.level = 1
AND vs.owner = 1111
3 ответа:
Прежде всего, чтобы быть полностью эквивалентным, первый запрос должен быть написан
SELECT mw.*, nvs.* FROM mst_words mw LEFT JOIN (SELECT * FROM vocab_stats WHERE owner = 1111) AS nvs ON mw.no = nvs.vocab_no WHERE (nvs.correct > 0 ) AND mw.level = 1
Так что mw.* и nvs.* вместе производят тот же набор, что и сингулярное число 2-го запроса *. Запрос, как вы написали, может использовать внутреннее соединение, так как он включает фильтр на nvs.правильный.
Общая форма
TABLEA LEFT JOIN TABLEB ON <CONDITION>
attempts
найти записи TableB, основанные на условии. В случае сбоя результаты из таблицы A сохраняются, а все столбцы из таблицы B устанавливаются в значение NULL. НапротивTABLEA INNER JOIN TABLEB ON <CONDITION>
Также
attempts
найти записи TableB, основанные на условии. однако , когда происходит сбой, конкретная запись из таблицы TableA удаляется из выходного результирующего набора.Стандарт ANSI для перекрестного соединения производит декартово произведениемежду двумя таблицами.
Смысл синтаксиса заключается в том, что каждая строка в таблице A соединяется с каждой строкой в таблице B. Таким образом, 4 строки В A и 3 строки В B производят 12 строк вывода. В паре с условиями в предложении WHERE это иногда производит то же самое поведение внутреннего соединения, так как они выражают то же самое (условие между A и B => keep или not). Тем не менее, это намного яснее, когда вы читаете о намерении, когда вы используете внутреннее соединение вместо запятых. С точки зрения производительности большинство СУБД обрабатывает левое соединение быстрее, чем внутреннее. Запятая может привести к тому, что системы баз данных неверно истолкуют намерение и выдадут плохой план запроса - так что еще один плюс для обозначения SQL92.TABLEA CROSS JOIN TABLEB -- # or in older syntax, simply using commas TABLEA, TABLEB
Зачем нам нужно левое соединение? если приведенного выше объяснения левого соединения все еще недостаточно (ведите записи в A без совпадений в B), то подумайте, что для достижения того же результата вам потребуется сложное объединение между двумя наборами, используя старую запятую для достижения того же эффекта. Но, как уже говорилось ранее, это не относится к вашему примеру, который на самом деле является внутренним соединением, скрывающимся за левым соединением.
Примечания:
- правое соединение то же самое, что и слева, за исключением того, что он начинается с TABLEB (правая сторона) вместо A.
Правое и левое соединения являются внешними соединениями. Слово OUTER является необязательным, то есть его можно записать какLEFT OUTER JOIN
. Третий тип внешнего соединения-полное внешнее соединение, но это здесь не обсуждается.
Отделение соединения от WHERE делает его легко читаемым, так как логику соединения нельзя спутать с условиями WHERE. Это также, как правило, будет быстрее, так как серверу не нужно будет выполнять два отдельных запроса и объединять результаты.
Два примера, которые вы привели, на самом деле не эквивалентны, так как вы включили подзапрос в первый пример. Это лучший пример:SELECT vs.*, mw.* FROM vocab_stats vs, mst_words mw LEFT JOIN vocab_stats vs ON mw.no = vs.vocab_no WHERE vs.correct > 0 AND mw.level = 1 AND vs.owner = 1111