Есть ли разница в эффективности явного и неявного внутреннего соединения? Например:
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;
используйте ключевое слово EXPLAIN, чтобы узнать разницу между обоими запросами ... используйте JOIN и увидите разницу ... Если вы попробуете в таблице более 100 тысяч записей, вы увидите разницу ...
@andrew Мой вопрос заключался в том, действительно ли неявное соединение было формой "взлома" (например, "Запрос, включающий более одной таблицы, без использования соединения? Это хакерство, не так ли?")
Они разные, неявное объединение время от времени будет удивлять вас при работе с нулевыми значениями; используйте явное объединение и избегайте ошибок, которые возникают, когда "ничего не изменилось!"
Нет никакой разницы. , - это CROSS JOIN с более свободным связыванием, а INNER JOIN - это CROSS JOIN с ON, как WHERE, но с более плотным связыванием. Для выполнения имеет значение то, как СУБД оптимизирует запросы.
Таким образом, вопрос должен заключаться в том, как каждая СУБД решает эту проблему. Например, я читал, что Oracle рекомендует использовать явные объединения, начиная с версии 10, но в документации не упоминается, есть ли разница, связанная с производительностью.
@EAmez То, что Oracle явное и неявное, заключается в том, чтобы избежать устаревшей не-ANSI нотации левого соединения (+), а не о запятой как внутреннем соединении. Старый синтаксис левого соединения не может обрабатывать все случаи левого соединения ключевого слова.
@philipxy то, что я пытался сказать, было: хорошо, если нет разницы между неявным и явным соединением, как вы говорите (и как я уже знал), тогда возникает вопрос, есть ли разница в производительности. Думаю, разницы нет, или не должно быть разницы, но точно не знаю. (Не стесняйтесь ответить на этот неявный вопрос).
@EAmez СУБД, которая не знает, что это тривиально эквивалентные запросы, имеет большие проблемы с производительностью, чем то, как она их реализует. Обоснование - это глава из учебника по реализации / оптимизации реляционных логических и физических запросов, а также руководство и / или документация по реализации для конкретной версии конкретной СУБД.
Я работал над проблемами leetcode SQL; их среда, кажется, работает на MySQL. И он не принимает явные соединения, предпочитая неявные соединения для "принятых" ответов. Это специфично для leetcode, или MySQL действительно не поддерживает неявные соединения?


С точки зрения производительности они точно такие же (по крайней мере, в SQL Server).
PS: имейте в виду, что синтаксис IMPLICIT OUTER JOIN устарел с SQL Server 2005. (Синтаксис IMPLICIT INNER JOIN, используемый в вопросе, все еще поддерживается)
Прекращение поддержки синтаксиса JOIN в "старом стиле": только отчасти
Синтаксис неявного соединения поддерживается SQL Server 2005 из коробки, но да, это плохая идея.
Хотя я предпочитаю явный синтаксис, можете ли вы объяснить, как они могут отказаться от неявных объединений? Идея, что это может быть устаревшим, кажется странной, а предположение, что они не поддерживаются SQL 2K5, неверно.
Можете ли вы предоставить подтверждающую документацию? Это звучит неправильно на нескольких уровнях.
Как вы осуждаете стандарт SQL?
Они не рекомендуют объединения внешний со старым синтаксисом, а не внутренние объединения. Причина в том, что их сложно исправить, и в некоторых случаях их можно удовлетворить с помощью разных планов выполнения, которые дают разные результаты.
@david Crenshaw, неявное соединение больше не входит в стандарт и не было в течение 18 лет.
В стандартном SQL неявное соединение не является внешним соединением. Это либо внутреннее соединение, либо перекрестное соединение.
Пожалуйста, предоставьте подтверждающие доказательства и дайте мне знать как-нибудь, и я сниму голос против. Или, по крайней мере, упомяните тест и измерение, которые вы использовали.
@lomaxx, просто для ясности, не могли бы вы указать синтаксис который для 2 в вопросе, который устарел?
Так называемые «неявные соединения» разновидности «внутреннего» или «перекрестного» остаются в Стандарте. SQL Server отказывается от синтаксиса внешнего соединения «старого стиля» (т. Е. *= и =*), который никогда не был стандартным.
это неправильно .. если JOIN не используется, возникает проблема с созданием большего количества строк по перекрестному произведению. используйте ключевое слово EXPLAIN, чтобы узнать разницу в запросах.
Я улучшил ответ с помощью внешней ссылки и четкого различия между устаревшим синтаксисом неявного внешнего соединения и синтаксисом неявного внутреннего соединения, который используется в вопросе.
@HLGEM это неверно. Синтаксис неявного соединения (FROM a, b, c) не считается устаревшим. Это все еще в стандартах SQL 2003+.
Старый синтаксис внешнего соединения (+) и *= никогда не был частью стандартного SQL. И это не имеет отношения к этому вопросу.
Лично я предпочитаю синтаксис соединения, поскольку он делает более ясным, что таблицы соединяются и как они соединяются. Попробуйте сравнить более крупные SQL-запросы, в которых вы выбираете из 8 разных таблиц, и у вас много фильтрации в where. Используя синтаксис соединения, вы отделяете части, в которых соединяются таблицы, от части, в которой вы фильтруете строки.
Полностью согласен, но это не по теме. ОП спросил об эффективности.
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, где это не имеет реального значения.
Ли, вы также можете использовать подсказки в неявных соединениях.
В Oracle крайне редко порядок соединения оказывает значимое влияние на план выполнения. См. Объяснение в Эта статья Джонатана Льюиса.
@lomaxx: Чтобы уточнить, я почти уверен, что оба приведенных выше синтаксиса поддерживаются SQL Serv 2005. Однако приведенный ниже синтаксис НЕ поддерживается
select a.*, b.*
from table a, table b
where a.id *= b.id;
В частности, внешнее соединение (* =) не поддерживается.
Честно говоря, я бы не стал использовать его даже в SQL Server 2000, синтаксис * = часто дает неправильные ответы. Иногда это интерпретируется как перекрестные соединения.
Первый ответ, который вы дали, использует так называемый синтаксис соединения ANSI, второй действителен и будет работать в любой реляционной базе данных.
Я согласен с grom, что вы должны использовать синтаксис соединения ANSI. По их словам, основная причина - ясность. Вместо того, чтобы иметь предложение where с множеством предикатов, некоторые из которых объединяют таблицы, а другие ограничивают строки, возвращаемые с синтаксисом соединения ANSI, вы делаете его ослепительно ясным, какие условия используются для объединения ваших таблиц, а какие используются для ограничения полученные результаты.
Как заявил Ли Колдуэлл, оптимизатор запросов может создавать разные планы запросов на основе того, что функционально выглядит как один и тот же оператор SQL. Для дальнейшего чтения ознакомьтесь с двумя следующими сообщениями в блогах: -
Одно сообщение от команды Oracle Optimizer
Еще одна запись из блога "Структурированные данные"
Надеюсь, вам это интересно.
Майк, разница, о которой они говорят, заключается в том, что вы должны быть уверены, что если вы укажете явное соединение, вы укажете условие присоединения для присоединения, а не фильтр. Вы заметите, что для семантически правильных запросов план выполнения такой же.
Второй синтаксис имеет нежелательную возможность перекрестного соединения: вы можете добавлять таблицы в часть FROM без соответствующего предложения WHERE. Это считается вредным.
Что, если имена таблиц в предложении from созданы из таблиц, используемых в предложении where?
вы также можете выполнить перекрестное соединение с явным синтаксисом JOIN. (stackoverflow.com/a/44438026/929164) вы, вероятно, имели в виду, что он менее строг и, следовательно, более подвержен ошибкам пользователя.
С точки зрения производительности это не должно иметь никакого значения. Синтаксис явного соединения кажется мне более понятным, поскольку он четко определяет отношения между таблицами в предложении 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 строк.
Это очень простой случай; это никоим образом не доказывает, что оптимизатор запросов не запутается и не сгенерирует другие планы в более сложном случае.
Это должен быть принятый ответ. Это правильно, план такой же (или близкий к более крупным операторам), но количество записей будет значительным, что приведет к разнице в производительности.
По моему опыту, использование синтаксиса cross-join-with-a-where-clause часто приводит к нарушению плана выполнения, особенно если вы используете продукт Microsoft SQL. Например, способ, которым SQL Server пытается оценить количество строк в таблице, ужасен. Использование синтаксиса внутреннего соединения дает вам некоторый контроль над выполнением запроса. Итак, с практической точки зрения, учитывая атавистический характер современной технологии баз данных, вы должны использовать внутреннее соединение.
У вас есть доказательства этого? Потому что принятый ответ говорит об обратном.
По сути, разница между ними в том, что один написан по-старому, а другой по-современному. Лично я предпочитаю современный сценарий, в котором используются определения 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, в которые писали многие люди, как старшие, так и молодые. Опять же, все сводится к тому, насколько читабелен сценарий и команда, с которой вы работаете.
Хороший вопрос. Мне любопытно, почему вообще используется явное соединение. Разве без него нельзя делать все запросы?