Явний vs неявний SQL приєднується


399

Чи є різниця в ефективності в явному відносно неявного внутрішнього з'єднання? Наприклад:

SELECT * FROM
table a INNER JOIN table b
ON a.id = b.id;

vs.

SELECT a.*, b.*
FROM table a, table b
WHERE a.id = b.id;

11
Хороше питання. Мені цікаво, чому явне з'єднання використовується взагалі. Неможливо зробити без нього всі запити?
andrew

6
використовуйте ключове слово EXPLAIN, щоб знати різницю в обох запитах .. використовуйте ПРИЄДНУЙТЕСЬ та
перевірте

@andrew Моє запитання було насправді, чи неявне приєднання було формою "хак" (як у "Запит, що включає більше однієї таблиці, не використовує приєднання? Це хак, чи не так?")
bobobobo

3
Вони різні, неявне приєднання здивує вас раз у раз при роботі з нульовими значеннями; використовувати явне приєднання і уникати помилок, які виникають, коли "нічого не змінилося!"
BlackTigerX

1
Різниці немає. ,це CROSS JOINз більш вільним і обов'язковим INNER JOINє CROSS JOINз ONяк , WHEREале міцніше палітурки. Важливим для виконання є те, як СУБД оптимізує запити.
philipxy

Відповіді:


132

Ефективні, вони точно такі ж (принаймні, у SQL Server).

PS: Майте на увазі, що IMPLICIT OUTER JOINсинтаксис застарілий з часу SQL Server 2005. ( IMPLICIT INNER JOINСинтаксис, який використовується у запитанні, все ще підтримується)

Позбавлення "старого стилю" ПРИЄДНАЙТЕ до синтаксису: лише часткова річ


4
@lomaxx, просто для наочності ви могли б вказати, який синтаксис 2 у питанні застарілий?
J Wynia

8
Чи можете ви надати супровідну документацію? Це звучить неправильно на кількох рівнях.
NotMe

21
Як ви застаріли стандарт SQL?
David Crawshaw

7
@david Crenshaw, неявна приєднання вже не є стандартом і вже 18 років.
HLGEM

11
Так звані "неявні з'єднання" сорту "внутрішні" або "хрестові" залишаються у Стандарті. SQL Server застарає синтаксис зовнішнього приєднання "старого" (тобто *=і =*), який ніколи не був стандартом.
onedaywhen

129

Особисто я віддаю перевагу синтаксису приєднання, оскільки він робить зрозумілішим, що таблиці об’єднані та як вони з’єднуються. Спробуйте порівняти більш великі SQL запити, коли ви вибираєте з 8 різних таблиць, і у вас багато фільтрування куди. Використовуючи синтаксис приєднання, ви відокремлюєте частини, де поєднуються таблиці, на ту частину, де ви фільтруєте рядки.


4
Я повністю погоджуюся, але це свого роду поза темою. ОП запитала про ефективність.
villasv

56

У MySQL 5.1.51 обидва запити мають однакові плани виконання:

mysql> explain select * from table1 a inner join table2 b on a.pid = b.pid;
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
| id | select_type | table | type | possible_keys | key  | key_len | ref          | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
|  1 | SIMPLE      | b     | ALL  | PRIMARY       | NULL | NULL    | NULL         |  986 |       |
|  1 | SIMPLE      | a     | ref  | pid           | pid  | 4       | schema.b.pid |   70 |       |
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
2 rows in set (0.02 sec)

mysql> explain select * from table1 a, table2 b where a.pid = b.pid;
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
| id | select_type | table | type | possible_keys | key  | key_len | ref          | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
|  1 | SIMPLE      | b     | ALL  | PRIMARY       | NULL | NULL    | NULL         |  986 |       |
|  1 | SIMPLE      | a     | ref  | pid           | pid  | 4       | schema.b.pid |   70 |       |
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
2 rows in set (0.00 sec)

table1має 166208 рядків; table2має близько 1000 рядів.

Це дуже простий випадок; це жодним чином не підтверджує, що оптимізатор запитів не заплутався б і не створив різні плани у складнішому випадку.


Це має бути прийнятою відповіддю. Це правильно, план такий же (або близький до більш великих заяв), але обсяг записів буде різким, тим самим спричиняючи різницю у виконанні.
Радянський кордон

37

Другий синтаксис має небажану можливість перехресного з'єднання: ви можете додавати таблиці до частини FROM без відповідного пункту WHERE. Це вважається шкідливим.


Що робити, якщо імена таблиць у пункті від породжуються з таблиць, які використовуються в пункті де?
Jus12

ви можете зробити перехресне з'єднання і з явним синтаксисом JOIN. ( stackoverflow.com/a/44438026/929164 ) ви, мабуть, мали на увазі, що він менш суворий, тим більше схильний до помилок користувача.
Даніель Дубовський

15

Перша відповідь, яку ви дали, використовує синтаксис приєднання ANSI, а другий є дійсним і працюватиме в будь-якій реляційній базі даних.

Я погоджуюся з grom, що ви повинні використовувати синтаксис приєднання ANSI. Як вони сказали, головна причина - в ясності. Замість того, щоб мати пункт де з великою кількістю предикатів, деякі з яких приєднуються до таблиць, а інші обмежують рядки, повернуті синтаксисом приєднання ANSI, ви даєте сліпо зрозуміти, які умови використовуються для приєднання до ваших таблиць, а які використовуються для обмеження результати.


5

Ефективні, вони абсолютно однакові (принаймні, у SQL Server), але пам’ятайте, що вони знецінюють цей синтаксис приєднання, і він не підтримує sql server2005 з вікна.

Я думаю, ви думаєте про застарілі оператори * = і = * проти "зовнішнього з'єднання".

Я тільки зараз перевірив два задані формати, і вони належним чином працюють у базі даних SQL Server 2008. У моєму випадку вони складали однакові плани виконання, але я не могла впевнено сказати, що це завжди буде правдою.


5

@lomaxx: Просто для уточнення я майже впевнений, що обидва вище синтаксису підтримуються SQL Serv 2005. Синтаксис нижче НЕ підтримується

select a.*, b.*  
from table a, table b  
where a.id *= b.id;

Зокрема, зовнішнє з'єднання (* =) не підтримується.


2
Чесно кажучи, я б не використовував його навіть у SQL Server 2000, синтаксис * = часто дає неправильні відповіді. Іноді це трактує як перехресне приєднання.
HLGEM

2

У деяких базах даних (зокрема Oracle) порядок з'єднань може змінити величину запитів (якщо існує більше двох таблиць). В одному застосуванні у нас було буквально два порядкові різниці в деяких випадках. Використання внутрішнього синтаксису приєднання дає вам контроль над цим - якщо ви використовуєте правильний підказки синтаксису.

Ви не вказали, яку базу даних використовуєте, але ймовірність підказує, що там SQL Server або MySQL не має жодної реальності.


1
Ле, ви можете використовувати підказки і в неявних приєднаннях.
SquareCog

1
В Oracle вкрай рідко наказ про приєднання впливає на план виконання змістовно. Дивіться цю статтю Джонатана Льюїса для пояснення.
Джон Хеллер

1

Як заявив Лей Колдвелл, оптимізатор запитів може створювати різні плани запитів, виходячи з того, що функціонально виглядає як той самий оператор SQL. Для подальшого читання з цього питання ознайомтеся з наступними двома публікаціями блогу:

Одне повідомлення від команди Oracle Optimizer

Ще одна публікація з блогу "Структуровані дані"

Сподіваюся, вам це цікаво.


Майк, різниця, про яку вони говорять, полягає в тому, що вам потрібно бути впевненим, що якщо ви вкажете явне з'єднання, ви вкажете умову приєднання, щоб приєднатись, а не фільтр. Ви зауважите, що для семантично правильних запитів план exec той самий.
SquareCog

1

Продуктивність мудра, вона не повинна мати жодних змін. Синтаксис явного приєднання видається мені більш зрозумілим, оскільки він чітко визначає взаємозв'язки між таблицями в пункті від і не захаращує пункт де.


0

В основному різниця між двома полягає в тому, що одна написана по-старому, а інша написана сучасним способом. Особисто я віддаю перевагу сучасному сценарію, використовуючи внутрішнє, ліве, зовнішнє, праве визначення, оскільки вони більш пояснювальні та роблять код більш читабельним.

При взаємодії з внутрішніми з'єднаннями немає ніякої реальної різниці в читабельності, однак це може ускладнитися при роботі з лівими та правими з'єднаннями, оскільки в старій методиці ви отримаєте щось подібне:

SELECT * 
FROM table a, table b
WHERE a.id = b.id (+);

Наведене - це старий спосіб написання лівого з'єднання на відміну від наступного:

SELECT * 
FROM table a 
LEFT JOIN table b ON a.id = b.id;

Як візуально бачите, сучасний спосіб написання сценарію робить запит більш читабельним. (До речі, це стосується правильних з'єднань і трохи складніше для зовнішніх з'єднань).

Повертаючись до пластини котла, це не має значення для компілятора SQL, як запитується запит, оскільки він обробляє їх однаково. Я бачив поєднання обох в базах даних Oracle, в яких багато людей записували, як старші, так і молодші. Знову ж таки, це зводиться до того, наскільки читабельний сценарій та команда, з якою ви розвиваєтеся.


-1

На моєму досвіді, використання синтаксису перехресних з’єднань-з-де-де часто створює план виконання мозку з пошкодженнями, особливо якщо ви використовуєте продукт Microsoft SQL. Наприклад, те, що SQL Server намагається оцінити кількість рядків таблиці, є жахливим. Використання внутрішнього синтаксису приєднання дає вам певний контроль над виконанням запиту. Тож з практичної точки зору, з огляду на атавістичний характер поточної технології баз даних, ви повинні піти з внутрішнім з'єднанням.


5
Чи є у вас якісь докази цього? Тому що прийнята відповідь говорить інакше.
cimmanon
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.