Явные и неявные SQL-соединения

Есть ли разница в эффективности явного и неявного внутреннего соединения? Например:

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

против.

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

Хороший вопрос. Мне любопытно, почему вообще используется явное соединение. Разве без него нельзя делать все запросы?

andrew 24.01.2011 01:45

используйте ключевое слово EXPLAIN, чтобы узнать разницу между обоими запросами ... используйте JOIN и увидите разницу ... Если вы попробуете в таблице более 100 тысяч записей, вы увидите разницу ...

Jeyanth Kumar 16.03.2012 12:38

@andrew Мой вопрос заключался в том, действительно ли неявное соединение было формой "взлома" (например, "Запрос, включающий более одной таблицы, без использования соединения? Это хакерство, не так ли?")

bobobobo 13.04.2013 04:53

Они разные, неявное объединение время от времени будет удивлять вас при работе с нулевыми значениями; используйте явное объединение и избегайте ошибок, которые возникают, когда "ничего не изменилось!"

BlackTigerX 04.09.2013 03:46

Нет никакой разницы. , - это CROSS JOIN с более свободным связыванием, а INNER JOIN - это CROSS JOIN с ON, как WHERE, но с более плотным связыванием. Для выполнения имеет значение то, как СУБД оптимизирует запросы.

philipxy 23.08.2017 00:52

Таким образом, вопрос должен заключаться в том, как каждая СУБД решает эту проблему. Например, я читал, что Oracle рекомендует использовать явные объединения, начиная с версии 10, но в документации не упоминается, есть ли разница, связанная с производительностью.

EAmez 06.08.2019 12:51

@EAmez То, что Oracle явное и неявное, заключается в том, чтобы избежать устаревшей не-ANSI нотации левого соединения (+), а не о запятой как внутреннем соединении. Старый синтаксис левого соединения не может обрабатывать все случаи левого соединения ключевого слова.

philipxy 11.09.2019 12:07

@philipxy то, что я пытался сказать, было: хорошо, если нет разницы между неявным и явным соединением, как вы говорите (и как я уже знал), тогда возникает вопрос, есть ли разница в производительности. Думаю, разницы нет, или не должно быть разницы, но точно не знаю. (Не стесняйтесь ответить на этот неявный вопрос).

EAmez 11.09.2019 13:45

@EAmez СУБД, которая не знает, что это тривиально эквивалентные запросы, имеет большие проблемы с производительностью, чем то, как она их реализует. Обоснование - это глава из учебника по реализации / оптимизации реляционных логических и физических запросов, а также руководство и / или документация по реализации для конкретной версии конкретной СУБД.

philipxy 13.10.2019 03:13

Я работал над проблемами leetcode SQL; их среда, кажется, работает на MySQL. И он не принимает явные соединения, предпочитая неявные соединения для "принятых" ответов. Это специфично для leetcode, или MySQL действительно не поддерживает неявные соединения?

j9000 17.01.2020 18:28
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
423
10
179 481
12
Перейти к ответу Данный вопрос помечен как решенный

Ответы 12

Ответ принят как подходящий

С точки зрения производительности они точно такие же (по крайней мере, в SQL Server).

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

Прекращение поддержки синтаксиса JOIN в "старом стиле": только отчасти

Синтаксис неявного соединения поддерживается SQL Server 2005 из коробки, но да, это плохая идея.

Cade Roux 22.10.2008 00:50

Хотя я предпочитаю явный синтаксис, можете ли вы объяснить, как они могут отказаться от неявных объединений? Идея, что это может быть устаревшим, кажется странной, а предположение, что они не поддерживаются SQL 2K5, неверно.

BlackWasp 28.12.2008 17:44

Можете ли вы предоставить подтверждающую документацию? Это звучит неправильно на нескольких уровнях.

NotMe 20.05.2009 18:28

Как вы осуждаете стандарт SQL?

David Crawshaw 30.09.2009 13:10

Они не рекомендуют объединения внешний со старым синтаксисом, а не внутренние объединения. Причина в том, что их сложно исправить, и в некоторых случаях их можно удовлетворить с помощью разных планов выполнения, которые дают разные результаты.

Lasse V. Karlsen 30.09.2009 13:10

@david Crenshaw, неявное соединение больше не входит в стандарт и не было в течение 18 лет.

HLGEM 22.06.2010 00:00

В стандартном SQL неявное соединение не является внешним соединением. Это либо внутреннее соединение, либо перекрестное соединение.

Marcus Adams 24.06.2010 20:25

Пожалуйста, предоставьте подтверждающие доказательства и дайте мне знать как-нибудь, и я сниму голос против. Или, по крайней мере, упомяните тест и измерение, которые вы использовали.

Alexander Bird 08.02.2011 07:30

@lomaxx, просто для ясности, не могли бы вы указать синтаксис который для 2 в вопросе, который устарел?

J Wynia 05.09.2008 04:01

Так называемые «неявные соединения» разновидности «внутреннего» или «перекрестного» остаются в Стандарте. SQL Server отказывается от синтаксиса внешнего соединения «старого стиля» (т. Е. *= и =*), который никогда не был стандартным.

onedaywhen 28.09.2011 21:08

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

Jeyanth Kumar 16.03.2012 12:36

Я улучшил ответ с помощью внешней ссылки и четкого различия между устаревшим синтаксисом неявного внешнего соединения и синтаксисом неявного внутреннего соединения, который используется в вопросе.

Jens Mühlenhoff 13.10.2013 17:48

@HLGEM это неверно. Синтаксис неявного соединения (FROM a, b, c) не считается устаревшим. Это все еще в стандартах SQL 2003+.

ypercubeᵀᴹ 18.06.2015 12:06

Старый синтаксис внешнего соединения (+) и *= никогда не был частью стандартного SQL. И это не имеет отношения к этому вопросу.

philipxy 23.08.2017 00:53

Лично я предпочитаю синтаксис соединения, поскольку он делает более ясным, что таблицы соединяются и как они соединяются. Попробуйте сравнить более крупные SQL-запросы, в которых вы выбираете из 8 разных таблиц, и у вас много фильтрации в where. Используя синтаксис соединения, вы отделяете части, в которых соединяются таблицы, от части, в которой вы фильтруете строки.

Полностью согласен, но это не по теме. ОП спросил об эффективности.

villasv 29.11.2017 16:01

Performance wise, they are exactly the same (at least in SQL Server) but be aware that they are deprecating this join syntax and it's not supported by sql server2005 out of the box.

Я думаю, вы думаете об устаревших операторах * = и = * против «внешнего соединения».

Я только что протестировал два приведенных формата, и они правильно работают в базе данных SQL Server 2008. В моем случае они дали идентичные планы выполнения, но я не мог с уверенностью сказать, что это всегда будет правдой.

В некоторых базах данных (особенно в Oracle) порядок объединений может иметь огромное значение для производительности запросов (если существует более двух таблиц). В одном приложении в некоторых случаях разница была буквально на два порядка. Использование синтаксиса внутреннего соединения дает вам контроль над этим - если вы используете правильный синтаксис подсказок.

Вы не указали, какую базу данных вы используете, но вероятность предполагает SQL Server или MySQL, где это не имеет реального значения.

Ли, вы также можете использовать подсказки в неявных соединениях.

SquareCog 30.10.2008 04:26

В Oracle крайне редко порядок соединения оказывает значимое влияние на план выполнения. См. Объяснение в Эта статья Джонатана Льюиса.

Jon Heller 25.06.2013 02:49

@lomaxx: Чтобы уточнить, я почти уверен, что оба приведенных выше синтаксиса поддерживаются SQL Serv 2005. Однако приведенный ниже синтаксис НЕ поддерживается

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

В частности, внешнее соединение (* =) не поддерживается.

Честно говоря, я бы не стал использовать его даже в SQL Server 2000, синтаксис * = часто дает неправильные ответы. Иногда это интерпретируется как перекрестные соединения.

HLGEM 18.03.2009 20:21

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

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

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

Одно сообщение от команды Oracle Optimizer

Еще одна запись из блога "Структурированные данные"

Надеюсь, вам это интересно.

Майк, разница, о которой они говорят, заключается в том, что вы должны быть уверены, что если вы укажете явное соединение, вы укажете условие присоединения для присоединения, а не фильтр. Вы заметите, что для семантически правильных запросов план выполнения такой же.

SquareCog 30.10.2008 04:34

Второй синтаксис имеет нежелательную возможность перекрестного соединения: вы можете добавлять таблицы в часть FROM без соответствующего предложения WHERE. Это считается вредным.

Что, если имена таблиц в предложении from созданы из таблиц, используемых в предложении where?

Jus12 02.09.2015 19:59

вы также можете выполнить перекрестное соединение с явным синтаксисом JOIN. (stackoverflow.com/a/44438026/929164) вы, вероятно, имели в виду, что он менее строг и, следовательно, более подвержен ошибкам пользователя.

Daniel Dubovski 02.01.2020 15:30

С точки зрения производительности это не должно иметь никакого значения. Синтаксис явного соединения кажется мне более понятным, поскольку он четко определяет отношения между таблицами в предложении from и не загромождает предложение where.

В 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 строк.

Это очень простой случай; это никоим образом не доказывает, что оптимизатор запросов не запутается и не сгенерирует другие планы в более сложном случае.

Это должен быть принятый ответ. Это правильно, план такой же (или близкий к более крупным операторам), но количество записей будет значительным, что приведет к разнице в производительности.

SovietFrontier 13.05.2019 19:16

По моему опыту, использование синтаксиса cross-join-with-a-where-clause часто приводит к нарушению плана выполнения, особенно если вы используете продукт Microsoft SQL. Например, способ, которым SQL Server пытается оценить количество строк в таблице, ужасен. Использование синтаксиса внутреннего соединения дает вам некоторый контроль над выполнением запроса. Итак, с практической точки зрения, учитывая атавистический характер современной технологии баз данных, вы должны использовать внутреннее соединение.

У вас есть доказательства этого? Потому что принятый ответ говорит об обратном.

cimmanon 13.08.2015 21:17

По сути, разница между ними в том, что один написан по-старому, а другой по-современному. Лично я предпочитаю современный сценарий, в котором используются определения internal, left, external, right, потому что они более понятны и делают код более читабельным.

При работе с внутренними соединениями нет никакой реальной разницы в удобочитаемости, однако это может усложниться при работе с левыми и правыми соединениями, поскольку в более старом методе вы получите что-то вроде этого:

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, в которые писали многие люди, как старшие, так и молодые. Опять же, все сводится к тому, насколько читабелен сценарий и команда, с которой вы работаете.

Другие вопросы по теме