
Как derived tables могут ускорить SQL в разы
Недавно оптимизировал огромный квери в проекте.
На первый взгляд всё выглядело нормально: запрос считал количество проданных билетов и оставшиеся места для каждого события.
Но под капотом использовались correlated subqueries — подзапросы, которые выполняются для каждой строки результата.
При большом количестве событий это превращается в сотни или тысячи повторных вычислений.
Решение оказалось довольно простым: заменить correlated subqueries на derived tables и один JOIN.
Это превращает:
N строк × подзапрос
в
1 агрегация + 1 JOIN
Упрощённый пример.
SELECT
e.*,
GREATEST(
0,
e.total_tickets
- (
SELECT COUNT(*)
FROM order_tickets ot
WHERE ot.event_id = e.id
AND ot.status = 'active'
)
) AS remaining_tickets
FROM events e
ORDER BY remaining_tickets DESC;
Для каждого события база выполняет:
COUNT(*) FROM order_tickets WHERE event_id = e.id
Фактически для каждого эвента запускай саб квери. Даже с индексами это всё равно повторяющаяся работа.
Derived table
Derived table — это подзапрос, который используется как временная таблица внутри SQL-запроса.
SELECT
e.*,
GREATEST(
0,
e.total_tickets - COALESCE(sold_agg.sold_count, 0)
) AS remaining_tickets
FROM events e
LEFT JOIN (
SELECT
event_id,
COUNT(*) AS sold_count
FROM order_tickets
WHERE status = 'active'
GROUP BY event_id
) sold_agg
ON sold_agg.event_id = e.id
ORDER BY remaining_tickets DESC;
Теперь база: Один раз агрегирует продажи
event_id → sold_count
Джойнит результат к событиям.
То есть вместо: N × subquery мы получаем 1 aggregation + 1 join
Она существует только во время выполнения запроса, но позволяет:
- заранее агрегировать данные
- уменьшить повторные вычисления
- упростить сложные JOIN-операции