Что лучше: многие присоединяются к условиям или многие, где условия?

13

Я пытаюсь сравнить два запроса:

Запрос 1:

SELECT a,b,c,d,e
FROM tableA
LEFT JOIN tableB
ON tableA.a=tableB.a
WHERE tableA.b=tableB.b AND tableA.c=tableB.c  AND tableA.d=tableB.d  AND tableA.e=tableB.e 

Запрос 2:

SELECT a,b,c,d,e
FROM tableA
LEFT JOIN tableB
ON tableA.a=tableB.a AND tableA.b=tableB.b AND tableA.c=tableB.c  AND tableA.d=tableB.d  
WHERE tableA.e=tableB.e 

Прав ли я сказать, что эти два запроса дают одинаковые результаты?

Кроме того, правильно ли сказать, что первый запрос создает большую таблицу, для которой необходимо выполнить большее WHEREусловие; тогда как во втором случае мы имеем меньшую построенную таблицу, к которой WHEREзатем применяется простое .

Предполагая, что результаты совпадают, какой запрос должен быть предпочтительным? Есть ли очевидная проблема с производительностью?

Geoff
источник
3
Нет, вы не правы, говоря это. Было бы, если бы это было INNER JOIN, но с LEFT JOINэтим будет возвращать другие результаты. В основном, условия, которые вы добавили в WHEREсвой второй запрос, конвертируют вас JOINвINNER JOIN
Lamak
Ах хорошо. Я следую тому, что вы говорите. Если я внесу изменения, чтобы INNER JOINмои вопросы о производительности остались в силе?
Джефф
4
Для внутренних соединений не должно быть различий в производительности. Тем не менее, для удобочитаемости и правильного выражения намерений, вы должны использовать критерии объединения в ONи критерии фильтрации в WHERE.
Аарон Бертран
@ypercube правильно, я пропустил это условие.
Ламак

Ответы:

10

Если мы считаем, что вы используете INNER JOINвместо LEFT JOIN(что, по-видимому, ваше намерение), эти два запроса функционально эквивалентны. Оптимизаторы запросов рассмотрят и оценят критерии в вашем WHEREпредложении и вашем FROMпредложении и учтут все эти факторы при построении планов запросов для достижения наиболее эффективного плана выполнения. Если мы выполним EXPLAINоба оператора, мы получим одинаковый результат:

Запрос 1 :

EXPLAIN
SELECT 
  tableA.ColA
  ,tableA.ColB
  ,tableA.ColC
  ,tableA.ColD
  ,tableA.ColE
FROM tableA
  JOIN tableB ON tableA.ColA=tableB.ColA
WHERE 
  tableA.ColB=tableB.ColB 
  AND tableA.ColC=tableB.ColC 
  AND tableA.ColD=tableB.ColD  
  AND tableA.ColE=tableB.ColE

[Результаты] :

| ID | SELECT_TYPE |  TABLE | TYPE | POSSIBLE_KEYS |    KEY | KEY_LEN |    REF | ROWS |                          EXTRA |
------------------------------------------------------------------------------------------------------------------------
|  1 |      SIMPLE | tableA |  ALL |        (null) | (null) |  (null) | (null) |    1 |                                |
|  1 |      SIMPLE | tableB |  ALL |        (null) | (null) |  (null) | (null) |    1 | Using where; Using join buffer |

Запрос 2 :

EXPLAIN
SELECT 
  tableA.ColA
  ,tableA.ColB
  ,tableA.ColC
  ,tableA.ColD
  ,tableA.ColE
FROM tableA
  JOIN tableB ON tableA.ColA=tableB.ColA
  AND tableA.ColB=tableB.ColB 
  AND tableA.ColC=tableB.ColC 
  AND tableA.ColD=tableB.ColD  
WHERE
  tableA.ColE=tableB.ColE

[Результаты] :

| ID | SELECT_TYPE |  TABLE | TYPE | POSSIBLE_KEYS |    KEY | KEY_LEN |    REF | ROWS |                          EXTRA |
------------------------------------------------------------------------------------------------------------------------
|  1 |      SIMPLE | tableA |  ALL |        (null) | (null) |  (null) | (null) |    1 |                                |
|  1 |      SIMPLE | tableB |  ALL |        (null) | (null) |  (null) | (null) |    1 | Using where; Using join buffer |

Вы можете просмотреть полную информацию по следующим ссылкам. Я также создал пример SQL 2008, чтобы вы могли сравнить, как работают два движка (что одинаково):

Пример запроса MySQL

Пример запроса SQL 2008 (убедитесь, что вы «Просмотреть план выполнения» для обоих результатов)

Майк Фал
источник
Спасибо за ваше подробное решение. Я попытался INNER JOINвместо, LEFT JOINи я получаю тот же результат в десятой части времени. Я думаю, я знаю, почему я получаю такой же результат, но почему бы INNER JOINиметь лучшую производительность?
Джефф
4
Как LEFT JOINи внешнее соединение, оно не может ограничить набор данных на стороне полного возврата набора и попытается извлечь все строки из этой таблицы (в данном случае, TableA). Если вы используете INNER JOIN, он может использовать эти критерии в обеих таблицах и ограничить набор данных, тем самым обеспечивая более быстрый возврат.
Майк Фал