Що краще: багато умов приєднання або багато, де умови?


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потім застосовується проста .

Якщо припустити, що результати однакові, якому запиту слід віддати перевагу? Чи є явна проблема ефективності?


3
Ні, ви неправі це сказати. Якби це було INNER JOIN, але LEFT JOINце призведе до різних результатів. В принципі, умови , які ви додали на WHEREна другому запиті перетворимо JOINза принципомINNER JOIN
Lamak

Добренько. Я стежу за тим, що ти кажеш. Якщо я редагую, щоб INNER JOINмої питання щодо продуктивності залишалися дійсними?
Джефф

4
Для INNER JOIN не повинно бути різниці у продуктивності. З огляду на це, для читабельності та правильного вираження намірів слід використовувати критерії приєднання у критеріях 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, він може використовувати ці критерії в обох таблицях і обмежувати набір даних, забезпечуючи тим самим більш швидке повернення.
Майк Фаль
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.