Коррелированные и некоррелированные подзапросы
Разберитесь с коррелированными подзапросами, обращающимися к внешней строке, их характеристиками производительности и случаями, когда EXISTS лучше IN
«Коррелированные и некоррелированные подзапросы» — бесплатный урок SQL Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения SQL Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс SQL Academy содержит 4 уроков всего.
Некоррелированные подзапросы
Некоррелированный подзапрос не ссылается на внешнюю строку. Он выполняется один раз, а его результат используется повторно:
SELECT * FROM users
WHERE id IN (
SELECT user_id FROM orders WHERE status = 'paid'
);Коррелированные подзапросы
Коррелированный подзапрос ссылается на внешнюю строку — логически он выполняется заново для каждой внешней строки:
SELECT u.id, u.email
FROM users u
WHERE EXISTS (
SELECT 1 FROM orders o
WHERE o.user_id = u.id
AND o.total > 1000
);Как определить разницу
Если внутренний SELECT ссылается на столбец из внешней конструкции FROM, подзапрос является коррелированным.
Влияние на производительность
Наивный коррелированный подзапрос имеет сложность O(внешнее × внутреннее). Современные планировщики часто переписывают его в полусоединение или хеш-соединение, но по возможности всё равно следует писать более простую форму.
EXISTS против IN
Для проверки «есть хотя бы одно совпадение»:
-- IN with non-correlated subquery (often the planner's favourite):
SELECT u.* FROM users u
WHERE u.id IN (SELECT user_id FROM orders);
-- EXISTS with correlated subquery (NULL-safe alternative):
SELECT u.* FROM users u
WHERE EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.id);NOT EXISTS всегда лучше NOT IN
NOT IN перестаёт работать, если внутренний набор содержит NULL. NOT EXISTS — нет. Для антисоединения всегда предпочитайте NOT EXISTS:
-- BUG-prone:
SELECT u.* FROM users u
WHERE u.id NOT IN (SELECT excluded_id FROM blocklist);
-- Safe:
SELECT u.* FROM users u
WHERE NOT EXISTS (SELECT 1 FROM blocklist b WHERE b.excluded_id = u.id);Коррелированные подзапросы в SELECT
Шаблон «поиск для каждой строки»:
SELECT u.id, u.email,
(SELECT MAX(created_at) FROM orders o WHERE o.user_id = u.id) AS last_order_at
FROM users u;
-- Often readable, but consider a LEFT JOIN + GROUP BY.Коррелированные подзапросы в UPDATE
Получайте производное значение для каждой строки:
UPDATE products p
SET review_count = (
SELECT COUNT(*) FROM reviews r WHERE r.product_id = p.id
);LATERAL JOIN: более понятный коррелированный шаблон
Для задачи «найти несколько строк для каждой внешней строки» LATERAL часто понятнее и быстрее — это рассматривается в уроке «Продвинутые шаблоны JOIN».
Кэширование подзапросов
PostgreSQL по умолчанию не кэширует результаты подзапросов между строками. Если один и тот же внутренний результат нужен много раз, используйте CTE.
Индексируйте столбец корреляции
Внутренний подзапрос фильтрует данные по ключу внешней строки. Без индекса по этому ключу для каждой внешней строки выполняется полное сканирование.
-- For the orders example, this is essential:
CREATE INDEX orders_user_id_idx ON orders(user_id);Итоги
Коррелированные подзапросы ссылаются на внешнюю строку.
- EXISTS — каноническая форма коррелированного подзапроса
- Предпочитайте NOT EXISTS вместо NOT IN
- Индексируйте столбец корреляции
- LATERAL — более понятная альтернатива во многих случаях
Проверка знаний
Почему NOT EXISTS безопаснее, чем NOT IN, если внутренний набор может содержать NULL?
Часто задаваемые вопросы
Урок «Коррелированные и некоррелированные подзапросы» бесплатный?
Да — полный текст урока «Коррелированные и некоррелированные подзапросы» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс SQL Academy, подпишись на CoddyKit PRO. Курс SQL Academy содержит 4 уроков всего.
Чему я научусь в уроке «Коррелированные и некоррелированные подзапросы»?
Разберитесь с коррелированными подзапросами, обращающимися к внешней строке, их характеристиками производительности и случаями, когда EXISTS лучше IN Ты практикуешь SQL Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать SQL Academy?
Предыдущий опыт не требуется. SQL Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.
Сколько времени занимает урок «Коррелированные и некоррелированные подзапросы»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке SQL Academy?
Да. Каждый урок SQL Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Скалярные, строковые и табличные подзапросы
- Коррелированные и некоррелированные подзапросы
- Общие табличные выражения (WITH)
- Рекурсивные CTE для иерархий