Подзапросы / CTEСредний
Подзапрос (Subquery)
SELECT внутри другого SQL выражения. Может быть в FROM, WHERE, HAVING или SELECT.
Синтаксис
-- В WHERE: SELECT * FROM t WHERE col IN (SELECT col FROM t2); -- В FROM: SELECT * FROM (SELECT ...) sub;
Объяснение
Подзапросы бывают:
- Некоррелированные: выполняются один раз, независимо от внешнего запроса
- Коррелированные: ссылаются на внешний запрос, выполняются для каждой строки — потенциально медленно
В большинстве случаев современные оптимизаторы могут переписать подзапрос как JOIN. Но не всегда — смотри EXPLAIN.
Пример
-- Некоррелированный (быстро — один раз) SELECT * FROM products WHERE category_id IN (SELECT id FROM categories WHERE is_active = true); -- Коррелированный (медленно — для каждой строки) SELECT name, (SELECT COUNT(*) FROM orders WHERE user_id = u.id) AS orders FROM users u;
Связанные термины
CTE (Common Table Expression)Именованный подзапрос, объявленный через WITH. Делает сложные запросы читаемыми.EXISTS / NOT EXISTSПроверяет, возвращает ли подзапрос хотя бы одну строку. Более эффективен чем IN для больших данных.INNER JOINВозвращает только строки, у которых есть совпадение в обеих таблицах.
Анекдоты по теме
DBA смотрит на запрос с 15 JOIN: — Ты зачем это написал? Разработчик: — Мне нужны все данные. DBA: — Тебе нужен психотерапевт. И денормализация.
Оптимизатор спрашивает у запроса: — Ты почему такой медленный? Запрос: — У меня в WHERE LIKE '%что-то%'. Оптимизатор: — Начальный процент? Запрос: — Ага. Оптимизатор: — Тогда я пас. Иди в full scan.
— Что такое seq_page_cost и random_page_cost? — Параметры PostgreSQL для оценки стоимости I/O. — По умолчанию random_page_cost = 4.0 (в 4 раза дороже seq). — На SSD? — Лучше поставить 1.1–1.5. Оптимизатор будет чаще использовать индексы. — Это действительно меняет планы? — Значительно.