Я - пользователь MySQL старой школы и всегда предпочитал JOIN
подзапрос. Но в настоящее время каждый использует подзапрос, и я ненавижу его; Я не знаю почему.
Мне не хватает теоретических знаний, чтобы судить самому, есть ли разница. Подзапрос так же хорош, как и, JOIN
и поэтому не о чем беспокоиться?
Ответы:
Взято из руководства MySQL ( 13.2.10.11 Перезапись подзапросов как объединений ):
Так что подзапросы могут быть медленнее, чем
LEFT [OUTER] JOIN
, но, на мой взгляд, их сила немного выше читаемости.источник
Join
иsub query
имеет другой синтаксис, поэтому читаемость мы не можем сравнить, оба имеют более высокую читаемость, если вы хорошо разбираетесь в синтаксисе SQL. Производительность важнее.Подзапросы - это логически правильный способ решения задач в форме «Получить факты из A, при условии наличия фактов из B». В таких случаях логичнее вставлять B в подзапрос, чем объединение. Это также более безопасно, в практическом смысле, так как вам не нужно быть осторожным в получении дублированных фактов от A из-за нескольких матчей против B.
На практике, однако, ответ обычно сводится к производительности. Некоторые оптимизаторы сосут лимоны, когда им дают соединение против подзапроса, а некоторые оптимизаторы сосут лимоны другим способом, и это зависит от оптимизатора, от версии СУБД и от запроса.
Исторически явные объединения обычно выигрывают, поэтому установившаяся мудрость в том, что объединения лучше, но оптимизаторы все время улучшаются, и поэтому я предпочитаю сначала писать запросы логически последовательным образом, а затем реструктурировать, если этого требуют ограничения производительности.
источник
select custid from cust join bought using (custid) where price > 500
. Если клиент купил несколько дорогих товаров, вы получите удвоение. Чтобы это исправитьselect custid from cust where exists (select * from bought where custid = cust.custid and price > 500)
. Вы можете использоватьselect distinct …
вместо этого, но это часто больше работы, либо для оптимизатора или оценщика.В большинстве случаев
JOIN
s быстрее, чем подзапросы, и очень редко подзапрос будет быстрее.В
JOIN
s RDBMS может создать план выполнения, который лучше для вашего запроса и может предсказать, какие данные должны быть загружены для обработки и сэкономить время, в отличие от подзапроса, где он будет выполнять все запросы и загружать все их данные для выполнения обработки. ,Хорошая вещь в подзапросах состоит в том, что они более читабельны, чем
JOIN
s: именно поэтому большинство новых людей SQL предпочитают их; это простой способ; но когда дело доходит до производительности, JOINS лучше в большинстве случаев, хотя их тоже нетрудно прочитать.источник
select * from a where a.x = (select b.x form b where b.id = a.id)
, чрезвычайно мало по сравнению с объединением. Это очень специфическая проблема, но в некоторых случаях она приносит вам от часов до минут.Используйте EXPLAIN, чтобы увидеть, как ваша база данных выполняет запрос к вашим данным. Существует огромное "это зависит" в этом ответе ...
PostgreSQL может переписать подзапрос в объединение или присоединение к подзапросу, когда он считает, что один быстрее другого. Все зависит от данных, индексов, корреляции, объема данных, запроса и т. Д.
источник
В 2010 году я присоединился бы к автору этого вопроса и за него бы решительно проголосовал
JOIN
, но с гораздо большим опытом (особенно в MySQL) я могу сказать: да, подзапросы могут быть лучше. Я прочитал несколько ответов здесь; некоторые заявленные подзапросы выполняются быстрее, но им не хватает хорошего объяснения. Я надеюсь, что смогу дать один (очень) поздний ответ:Прежде всего, позвольте мне сказать самое важное: существуют различные формы подзапросов
И второе важное утверждение: размер имеет значение
Если вы используете подзапросы , вы должны знать, как DB-Server выполняет подзапрос. Особенно, если подзапрос оценивается один раз или для каждой строки! С другой стороны, современный DB-сервер способен многое оптимизировать. В некоторых случаях подзапрос помогает оптимизировать запрос, но более новая версия DB-Server может сделать оптимизацию устаревшей.
Подзапросы в полях выбора
Имейте в виду, что подзапрос выполняется для каждой результирующей строки из
foo
.Избегайте этого, если это возможно; это может значительно замедлить ваш запрос на огромных наборах данных. Однако, если подзапрос не имеет ссылки на
foo
него, он может быть оптимизирован DB-сервером как статический контент и может быть оценен только один раз.Подзапросы в выражении Where
Если вам повезет, БД оптимизирует это внутренне в
JOIN
. Если нет, ваш запрос станет очень, очень медленным для огромных наборов данных, потому что он будет выполнять подзапрос для каждой строкиfoo
, а не только для результатов, как в типе выбора.Подзапросы в сообщении Join
Это интересно. Мы объединяем
JOIN
с подзапросом. И здесь мы получаем реальную силу подзапросов. Представьте набор данных с миллионами строк,wilco
но только с несколькими отдельнымиme
. Вместо того, чтобы объединяться с огромным столом, теперь у нас есть меньшая временная таблица, с которой можно соединиться. Это может привести к гораздо более быстрым запросам в зависимости от размера базы данных. Вы можете получить тот же эффект с помощьюCREATE TEMPORARY TABLE ...
иINSERT INTO ... SELECT ...
, что может обеспечить лучшую читаемость для очень сложных запросов (но может заблокировать наборы данных на повторяющемся уровне изоляции для чтения).Вложенные подзапросы
Вы можете вкладывать подзапросы на нескольких уровнях. Это может помочь с огромными наборами данных, если вам нужно сгруппировать или отсортировать результаты. Обычно DB-Server создает временную таблицу для этого, но иногда вам не нужно сортировать по всей таблице, только по набору результатов. Это может обеспечить гораздо лучшую производительность в зависимости от размера таблицы.
Вывод
Подзапросы не являются заменой для a,
JOIN
и вы не должны использовать их таким образом (хотя это возможно). По моему скромному мнению, правильное использование подзапроса - это использование в качестве быстрой заменыCREATE TEMPORARY TABLE ...
. Хороший подзапрос уменьшает набор данных так, как вы не можете выполнить вON
выражении aJOIN
. Если подзапрос имеет одно из ключевых словGROUP BY
или,DISTINCT
и предпочтительно не находится в полях выбора или операторе where, то это может значительно повысить производительность.источник
Sub-queries in the Join-statement
: (1) генерация производной таблицы из самого подзапроса может занять очень много времени. (2) полученная производная таблица не индексируется. только эти два могут значительно замедлить SQL.10
записей, так как нет индекса, это все равно означает, что потенциально можно запросить в 9 раз больше записей данных, чем без временной таблицы при присоединении к другим таблицам. Кстати, у меня была эта проблема раньше с моей БД (MySQL), в моем случае, использование подзапроса вSELECT list
может быть намного быстрее.EXPLAIN
запрос перед оптимизацией. Со старымset profiling=1
вы могли легко увидеть, является ли временное место узким местом. И даже для индекса требуется время обработки, B-Trees оптимизируют запросы для записей, но таблица из 10 записей может быть намного быстрее, чем индекс для миллионов записей. Но это зависит от множества факторов, таких как размеры и типы полей.Прежде всего, чтобы сравнить два первых, вы должны различать запросы с подзапросами:
Для первого класса запросов хорошая СУБД будет рассматривать соединения и подзапросы как эквивалентные и создавать одинаковые планы запросов.
В эти дни даже MySQL делает это.
Тем не менее, иногда это не так, но это не означает, что объединения всегда будут выигрывать - у меня были случаи, когда использование подзапросов в MySQL улучшало производительность. (Например, если что-то мешает планировщику mysql правильно оценить стоимость, и если планировщик не видит вариант соединения и вариант подзапроса одинаковыми, то подзапросы могут превзойти объединения, форсируя определенный путь).
Вывод заключается в том, что вы должны проверить свои запросы как для вариантов соединения, так и для вариантов подзапросов, если хотите убедиться, какой из них будет работать лучше.
Для второго класса сравнение не имеет смысла, так как эти запросы не могут быть переписаны с использованием объединений, и в этих случаях подзапросы являются естественным способом выполнения требуемых задач, и вы не должны их различать.
источник
Я думаю, что в приведенных ответах было подчеркнуто, что существует проблема дубликатов и проблемных результатов, которые могут возникнуть в конкретных случаях (использования).
(хотя Марсело Кантос упоминает об этом)
Я приведу пример из курсов Стэнфорда Lagunita по SQL.
Студенческий стол
Применить таблицу
(заявки, поданные в конкретные университеты и специальности)
Давайте попробуем найти баллы GPA для студентов, которые подали заявление по
CS
специальности (независимо от университета)Использование подзапроса:
Среднее значение для этого набора результатов:
Используя соединение:
среднее значение для этого набора результатов:
Очевидно, что вторая попытка дает ложные результаты в нашем случае использования, учитывая, что она подсчитывает дубликаты для вычисления среднего значения. Также очевидно, что использование
distinct
с оператором на основе соединения не устранит проблему, учитывая, что оно будет ошибочно удерживать одно из трех вхождений3.9
партитуры. Правильный случай заключается в учете ДВУХ (2) вхождений3.9
балла, учитывая, что у нас действительно ДВУХ (2) учеников с таким баллом, которые соответствуют нашим критериям запроса.Кажется, что в некоторых случаях подзапрос является самым безопасным способом, помимо каких-либо проблем с производительностью.
источник
Документация MSDN для SQL Server говорит
так что если вам нужно что-то вроде
попробуйте вместо этого использовать соединение. В других случаях это не имеет значения.
Я говорю: создание функций для подзапросов устраняет проблему беспорядка и позволяет реализовать дополнительную логику для подзапросов. Поэтому я рекомендую по возможности создавать функции для подзапросов.
Беспорядок в коде - большая проблема, и отрасль работает над тем, чтобы ее избегать десятилетиями.
источник
NOT EXISTS
. ANOT EXISTS
выигрывает поLEFT OUTER JOIN
разным причинам: предварительная производительность, отказоустойчивость (в случае столбцов с числами) и удобочитаемость. sqlperformance.com/2012/12/t-sql-queries/left-anti-semi-joinЗапустите очень большую базу данных из старой Mambo CMS:
0 секунд
~ 3 секунды
Объяснение показывает, что они проверяют одинаковое количество строк, но одна занимает 3 секунды, а одна почти мгновенная. Мораль истории? Если важна производительность (когда это не так?), Попробуйте несколько способов и посмотрите, какой из них самый быстрый.
А также...
0 секунд
Опять те же результаты, такое же количество проверенных строк. Я предполагаю, что DISTINCT mos_content.catid занимает гораздо больше времени, чем DISTINCT mos_categories.id.
источник
id
а не назван как-то такcatid
? Попытка оптимизировать мой доступ к БД, и ваши знания могут помочь.По моим наблюдениям, как в двух случаях, если в таблице менее 100 000 записей, соединение будет работать быстро.
Но в случае, если в таблице более 100 000 записей, лучшим результатом будет подзапрос.
У меня есть одна таблица, в которой 500 000 записей, которые я создал ниже запроса, и время его результата, как
источник
Подзапросы обычно используются для возврата одной строки в качестве атомарного значения, хотя они могут использоваться для сравнения значений с несколькими строками с помощью ключевого слова IN. Они допускаются практически в любой значимой точке инструкции SQL, включая список целей, предложение WHERE и т. Д. Простой подзапрос может быть использован в качестве условия поиска. Например, между парой таблиц:
Обратите внимание, что использование оператора нормального значения в результатах подзапроса требует, чтобы возвращалось только одно поле. Если вы заинтересованы в проверке существования одного значения в наборе других значений, используйте IN:
Это, очевидно, отличается от, скажем, LEFT-JOIN, где вы просто хотите объединить материал из таблиц A и B, даже если условие соединения не находит подходящей записи в таблице B и т. Д.
Если вы просто беспокоитесь о скорости, вам нужно проверить свою базу данных и написать хороший запрос и посмотреть, есть ли существенная разница в производительности.
источник
Версия MySQL: 5.5.28-0ubuntu0.12.04.2-log
У меня также сложилось впечатление, что JOIN всегда лучше, чем подзапрос в MySQL, но EXPLAIN - лучший способ сделать суждение. Вот пример, где подзапросы работают лучше, чем JOIN.
Вот мой запрос с 3 подзапросами:
ПОЯСНИТЕ показывает:
Тот же запрос с JOINs:
и вывод:
Сравнение
rows
столбца показывает разницу, и используется запрос с JOINUsing temporary; Using filesort
.Конечно, когда я выполняю оба запроса, первый выполняется за 0,02 секунды, второй не завершается даже через 1 минуту, поэтому EXPLAIN объяснил эти запросы правильно.
Если у меня нет INNER JOIN на
list_tag
столе, т.е. если я удаляюиз первого запроса и соответственно:
из второго запроса EXPLAIN возвращает одинаковое количество строк для обоих запросов, и оба эти запроса выполняются одинаково быстро.
источник
Подзапросы имеют возможность вычислять функции агрегации на лету. Например, найдите минимальную цену книги и получите все книги, которые продаются по этой цене. 1) Использование подзапросов:
2) с помощью JOIN
источник
GROUP BY
s с разными таблицами: stackoverflow.com/questions/11415284/… Подзапросы кажутся строго более общими. Смотрите также MySQL man: dev.mysql.com/doc/refman/5.7/en/optimizing-subqueries.html | dev.mysql.com/doc/refman/5.7/ru/rewriting-subqueries.htmlНекоторые люди говорят, что «некоторые СУБД могут переписать подзапрос в объединение или в присоединение к подзапросу, когда он считает, что один из них быстрее другого», но это утверждение относится к простым случаям, конечно, не для сложных запросов с подзапросами, которые на самом деле вызывают проблемы с производительностью.
источник
Разница видна только тогда, когда вторая объединяющая таблица имеет значительно больше данных, чем первичная таблица. У меня был опыт, как показано ниже ...
У нас была таблица пользователей из ста тысяч записей, а их данные о членстве (дружба) - около трехсот тысяч записей. Это было заявление о присоединении, чтобы взять друзей и их данные, но с большой задержкой. Но это работало нормально, когда в таблице участников было только небольшое количество данных. Как только мы изменили его, чтобы использовать подзапрос, он работал нормально.
Но в то же время запросы соединения работают с другими таблицами, в которых меньше записей, чем в основной таблице.
Поэтому я думаю, что операторы соединения и подзапроса работают нормально, и это зависит от данных и ситуации.
источник
В наши дни многие базы данных могут оптимизировать подзапросы и объединения. Таким образом, вы просто должны проверить свой запрос, используя объяснение, и посмотреть, какой из них быстрее. Если разница в производительности невелика, я предпочитаю использовать подзапросы, поскольку они просты и понятны.
источник
Я просто думаю о той же проблеме, но я использую подзапрос в части FROM. Мне нужно подключиться и запросить из больших таблиц, в «ведомой» таблице содержится 28 миллионов записей, но результат всего 128, так что малый результат - большие данные! Я использую функцию MAX () на нем.
Во-первых, я использую LEFT JOIN, потому что я думаю, что это правильный путь, mysql может оптимизировать и т. Д. Во второй раз, просто для тестирования, я переписываю для дополнительного выбора против JOIN.
Время выполнения левого соединения: 1.12 с Время выполнения SUB-SELECT: 0.06 с
В 18 раз быстрее выбор, чем объединение! Просто в ад Чокито. Подвыбор выглядит ужасно, но результат ...
источник
Если вы хотите ускорить ваш запрос с помощью соединения:
Для «внутреннего соединения / соединения» не используйте условие «вместо», вместо этого используйте его в состоянии «ВКЛ». Например:
Для «левого / правого соединения», не используйте в состоянии «ON», потому что, если вы используете левое / правое соединение, оно получит все строки для любой таблицы. Так что, не используйте его в «On». Итак, попробуйте использовать условие «Где»
источник