Левое соединение или выбор из нескольких таблиц с помощью запятой (,) [дубликат]


На этот вопрос уже есть ответ здесь:

Мне любопытно, почему мы должны использовать 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 14

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 для перекрестного соединения производит декартово произведениемежду двумя таблицами.

TABLEA CROSS JOIN TABLEB
  -- # or in older syntax, simply using commas
TABLEA, TABLEB
Смысл синтаксиса заключается в том, что каждая строка в таблице A соединяется с каждой строкой в таблице B. Таким образом, 4 строки В A и 3 строки В B производят 12 строк вывода. В паре с условиями в предложении WHERE это иногда производит то же самое поведение внутреннего соединения, так как они выражают то же самое (условие между A и B => keep или not). Тем не менее, это намного яснее, когда вы читаете о намерении, когда вы используете внутреннее соединение вместо запятых. С точки зрения производительности большинство СУБД обрабатывает левое соединение быстрее, чем внутреннее. Запятая может привести к тому, что системы баз данных неверно истолкуют намерение и выдадут плохой план запроса - так что еще один плюс для обозначения SQL92.

Зачем нам нужно левое соединение? если приведенного выше объяснения левого соединения все еще недостаточно (ведите записи в 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