В 2010 году я присоединился бы к автору этого вопроса и решительно проголосовал бы за JOIN
. Но с гораздо большим опытом (особенно в MySQL) я могу сказать: да, подзапросы могут быть лучше. Я прочитал несколько ответов здесь. Некоторые заявили, что подзапросы выполняются быстрее, но им не хватает хорошего объяснения Я надеюсь, что смогу дать один (очень) поздний ответ:
Прежде всего, позвольте мне сказать самое важное: Существуют различные формы подзапросов
И второе важное утверждение: Размер имеет значение
Если вы используете подзапросы, вы должны знать , как DB-сервер выполняет подзапрос. Особенно , если подзапрос оценивается один раз или для каждой строки!
С другой стороны, современный DB-сервер способен многое оптимизировать. В некоторых случаях подзапрос помогает оптимизировать запрос, но более новая версия DB-Server может сделать оптимизацию устаревшей.
Подзапросы в полях выбора
SELECT moo, (SELECT roger FROM wilco WHERE moo = me) AS bar FROM foo
Имейте в виду, что подзапрос выполняется для каждой результирующей строки из foo
. Избегайте этого, если это возможно, это может значительно замедлить ваш запрос к огромным наборам данных. Но если подзапрос не имеет ссылки на foo
, он может быть оптимизирован DB-сервером как статический контент и может быть оценен только один раз.
Подзапросы в операторе Where
SELECT moo FROM foo WHERE bar = (SELECT roger FROM wilco WHERE moo = me)
Если вам повезет, БД оптимизирует это внутренне до JOIN
. Если нет, ваш запрос станет очень, очень медленным для огромных наборов данных, потому что он будет выполнять подзапрос для каждой строки в foo
, а не только результаты, как в типе выбора.
Подзапросы в операторе соединения
SELECT moo, bar
FROM foo
LEFT JOIN (
SELECT MIN(bar), me FROM wilco GROUP BY me
) ON moo = me
Это интересно. Мы объединяем JOIN
с подзапросом. И здесь мы получаем реальную силу подзапросов. Представьте себе набор данных с миллионами строк в wilco
, но только с несколькими отдельными me
. Вместо того, чтобы объединяться с огромным столом, теперь у нас есть меньшая временная таблица, с которой можно соединиться. Это может привести к гораздо более быстрым запросам, в зависимости от размера базы данных. Вы можете получить тот же эффект с CREATE TEMPORARY TABLE ...
и INSERT INTO ... SELECT ...
, что может обеспечить лучшую читаемость для очень сложных запросов (но может блокировать наборы данных на повторяющемся уровне изоляции для чтения).
Вложенные подзапросы
SELECT moo, bar
FROM (
SELECT moo, CONCAT(roger, wilco) AS bar
FROM foo
GROUP BY moo
HAVING bar LIKE 'SpaceQ%'
) AS temp_foo
GROUP BY bar
ORDER BY bar
Вы можете вкладывать подзапросы на нескольких уровнях. Это может помочь в огромных наборах данных, если вам нужно сгруппировать или отсортировать результаты. Обычно DB-Server создает временную таблицу для этого, но иногда вам не нужно сортировать всю таблицу, а только набор результатов. Это может обеспечить гораздо лучшую производительность в зависимости от размера таблицы.
Заключение
Подзапросы не заменяют JOIN
, и вы не должны использовать их таким образом (хотя это возможно). По моему скромному мнению, правильное использование подзапроса - это использование в качестве быстрой замены CREATE TEMPORARY TABLE ...
. Хороший подзапрос уменьшает набор данных таким способом, которого вы не можете выполнить с помощью ON
оператора JOIN
. Если подзапрос имеет одно из ключевых слов GROUP BY
или DISTINCT
и предпочтительно не находится в полях выбора или операторе where, то это может значительно повысить производительность.