Производительность внутреннего соединения по сравнению с перекрестным соединением - PullRequest
48 голосов
/ 22 марта 2009

Эффект выдачи внутреннего соединения аналогичен указанию перекрестного соединения с условием соединения в предложении WHERE. Я заметил, что многие люди в моей компании используют перекрестные соединения, где я использую внутренние соединения. Я не заметил какого-либо значительного прироста производительности после изменения некоторых из этих запросов и задавался вопросом, было ли это просто совпадением или СУБД прозрачно оптимизирует такие проблемы (MySql в нашем случае). И вот конкретный пример для обсуждения:

SELECT User.*
FROM User, Address
WHERE User.addressId = Address.id;

SELECT User.*
FROM User
INNER JOIN Address ON (User.addressId = Address.id);

Ответы [ 10 ]

48 голосов
/ 22 марта 2009

Перекрестные объединения дают результаты, которые состоят из каждой комбинации строк из двух или более таблиц. Это означает, что если таблица A имеет 6 строк, а таблица B имеет 3 строки, перекрестное соединение приведет к 18 строкам. Между этими двумя таблицами не установлено никаких отношений - вы буквально просто производите каждую возможную комбинацию.

При внутреннем объединении значения столбцов из одной строки таблицы объединяются со значениями столбцов из другой строки другой (или той же) таблицы, образуя единую строку данных.

Если предложение WHERE добавляется в перекрестное соединение, оно ведет себя как внутреннее соединение, поскольку WHERE накладывает ограничивающий фактор.

Пока ваши запросы подчиняются здравому смыслу и конкретным рекомендациям по производительности , мне нравится думать о том, какое решение использовать тип объединения - просто вопрос вкуса.

23 голосов
/ 22 марта 2009

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

14 голосов
/ 22 марта 2009

Используйте EXPLAIN , чтобы просмотреть план запроса для обоих запросов и посмотреть, есть ли разница. Вполне возможно, MySQL будет использовать один и тот же план выполнения в обоих случаях. Я использую синтаксис INNER JOIN главным образом потому, что он намного понятнее.

10 голосов
/ 25 марта 2009

Я считаю, что рабочие места, которые допускают первый синтаксис (таблицы, разделенные запятыми), как правило, занимают значительное время в случаях отладки, когда возвращается больше строк, чем предполагалось. Непреднамеренные перекрестные объединения являются проблемой системы и могут поставить на колени даже самую хорошо настроенную базу данных. Это привело к тому, что наша система предварительного производства остановилась как минимум два раза в прошлом году.

Второй синтаксис (синтаксис соединения) заставляет автора думать о том, как таблицы сначала объединяются, а затем только возвращать интересные строки. Невозможно случайно выполнить перекрестное соединение, используя этот синтаксис, и, таким образом, опасность случайных неэффективных запросов уменьшается.

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

2 голосов
/ 23 марта 2009

Первый пример функционально такой же, как и второй. Однако этого синтаксиса следует избегать по нескольким причинам. Во-первых, гораздо проще случайно получить перекрестное объединение при использовании этого синтаксиса, особенно когда в таблице есть несколько объединений. Если вы видите много запросов такого типа с разными ключевыми словами, возможно, у вас есть кто-то, кто пытается исправить перекрестные объединения.

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

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

1 голос
/ 27 апреля 2011

Еще одним преимуществом первого синтаксиса является то, что вы можете быть более общими в своем предельном состоянии. Не только равенство.

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

1 голос
/ 22 марта 2009

Порядок, в котором вы присоединяетесь к столам или ставите условия ON / WHERE, не должен иметь значения.

Оптимизатор запросов должен в любом случае оптимизировать и использовать лучший порядок (и выбирать, как лучше всего фильтровать данные, с чего начать и т. Д.)

Однако, как и многим другим, я предлагаю использовать синтаксис INNER JOIN, так как он делает вещи более читабельными, он более прозрачен с синтаксисом LEFT или FULL соединений.

Здесь есть несколько более подробный текст: http://linus.brimstedt.se/?/article/articleview/SQL Синтаксис

/ B

0 голосов
/ 05 августа 2015

Объяснение обоих запросов дает одинаковый вывод

mysql> explain select * from t T1, t T2 where T1.ID=T2.ID;
+----+-------------+-------+------+---------------+------+---------+------+------+--------------------------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra                          |
+----+-------------+-------+------+---------------+------+---------+------+------+--------------------------------+
|  1 | SIMPLE      | T1    | ALL  | PRIMARY       | NULL | NULL    | NULL |    3 |                                |
|  1 | SIMPLE      | T2    | ALL  | PRIMARY       | NULL | NULL    | NULL |    3 | Using where; Using join buffer |
+----+-------------+-------+------+---------------+------+---------+------+------+--------------------------------+
2 rows in set (0.00 sec)

mysql> explain select * from t T1  join t T2 on T1.ID=T2.ID;
+----+-------------+-------+------+---------------+------+---------+------+------+--------------------------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra                          |
+----+-------------+-------+------+---------------+------+---------+------+------+--------------------------------+
|  1 | SIMPLE      | T1    | ALL  | PRIMARY       | NULL | NULL    | NULL |    3 |                                |
|  1 | SIMPLE      | T2    | ALL  | PRIMARY       | NULL | NULL    | NULL |    3 | Using where; Using join buffer |
+----+-------------+-------+------+---------------+------+---------+------+------+--------------------------------+
2 rows in set (0.00 sec)

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

0 голосов
/ 21 июня 2011

С начала времен оптимизаторы строились на основе классического синтаксиса продукта Restrict-Project-Cartesian. Практически все поставщики скопировали дизайн, впервые предложенный System R. Затем, неохотно, поставщики приняли «самый последний и лучший» синтаксис ANSI и модернизировали свои механизмы выполнения SQL. Вопреки тому, что вам может рассказать маркетинговая брошюра («используйте самый последний синтаксис»), мало что изменилось на физическом уровне реализации: это все еще [проиндексированные] вложенные циклы, или соединение с хешем или сортировкой-слиянием. Следовательно, нет оснований предполагать превосходство одного синтаксиса над другим.

На мой личный вкус, новый синтаксис избыточен , шумный и несовместим . Что касается санкций со стороны комитета, «зайдите в любой парк в каждом городе, и вы не найдете статую комитета».

0 голосов
/ 21 июня 2011

SQL Server сказал: «Когда WHERE превращает перекрестное соединение во внутреннее соединение», так что нет разницы. http://msdn.microsoft.com/en-us/library/ms190690.aspx

Я сделал SQL-сервер "План выполнения" Производительность такая же.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...