Когда использовать SQL подзапросы против стандартного присоединиться?

Я работаю над переписыванием некоторых плохо написанных SQL-запросов, и они чрезмерно используют подзапросы. Я ищу лучшие практики в отношении использования подзапросов.

любая помощь будет оценили.

3 ответов


подзапросы обычно прекрасны, если они не зависимые подзапросы (также известный как коррелированные подзапросы). Если вы используете только независимые подзапросы, и они используют соответствующие индексы, они должны выполняться быстро. Если у вас есть зависимый подзапрос, могут возникнуть проблемы с производительностью, поскольку зависимый подзапрос обычно должен выполняться один раз для каждой строки во внешнем запросе. Поэтому, если ваш внешний запрос имеет 1000 строк, подзапрос будет запущен 1000 раз. С другой стороны, независимый подзапрос обычно должен оцениваться только один раз.

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

Если вы получаете синтаксическую ошибку, потому что она ссылается на некоторые таблицы вне подзапроса, то ее dependent subquery.

общее правило, конечно, имеет несколько исключения. Например:

  • многие оптимизаторы могут взять зависимый подзапрос и найти способ эффективно запустить его как соединение. Например, запрос not EXISTS может привести к плану запроса ANTI JOIN, поэтому он не обязательно будет медленнее, чем запись запроса с соединением.
  • MySQL имеет ошибка где независимый подзапрос внутри выражения IN неправильно идентифицируется как зависимый подзапрос и поэтому используется неоптимальный план запроса. Этот видимо исправлено в новейших версиях MySQL.

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


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

select nickname, (select top 1 votedate from votes where user_id=u.id order by 1 desc)
from users u

С другой стороны, запросы EXISTS и NOT EXISTS одержат победу над соединениями.

select ...
where NOT EXISTS (.....)

обычно быстрее, чем

select ...
FROM A LEFT JOIN B
where B.ID is null

но даже эти обобщения могут быть неверно для любой конкретной схемы и распределения данных.


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