Разбери медленный SQL-запрос и дай переписанную версию, которая возвращает ТОТ ЖЕ результат.
СУБД: [СУБД: PostgreSQL 16]
Запрос (замени на свой, этот рабочий — с ним промпт запускается как есть):
[SQL: SELECT c.id, c.name, (SELECT COUNT(*) FROM orders o WHERE o.client_id = c.id) AS cnt FROM clients c LEFT JOIN orders o2 ON o2.client_id = c.id WHERE c.city = 'Москва' AND o2.created_at > now() - interval '30 days' GROUP BY c.id, c.name ORDER BY cnt DESC LIMIT 50]
План выполнения:
[EXPLAIN: Seq Scan on clients (cost=0.00..18234.00 rows=412 width=36); SubPlan 1 -> Aggregate; Seq Scan on orders (cost=0.00..44.12 rows=9 width=0)]
Размер таблиц: [ОБЪЁМ: clients 400 тыс. строк, orders 18 млн строк, растёт на 40 тыс. в день]
Что нужно:
1. Что именно делает запрос медленным — по строкам плана, а не по общим соображениям.
2. Индексы: `CREATE INDEX` целиком, с точным порядком колонок, и почему порядок такой.
3. Переписанный запрос.
4. Чем новый план будет отличаться: какие операции уйдут, какие останутся.
5. Как проверить, что результат не изменился — конкретный запрос сверки на своих данных.
Отсечка. Не пиши «добавьте индекс на нужные поля» — нужны имена колонок и порядок, иначе совет
бесполезен. Не меняй семантику: если в исходнике LEFT JOIN, результат с INNER JOIN — это другой
ответ, а не оптимизация. Не предлагай сменить СУБД, добавить кеш или денормализовать таблицу,
пока не исчерпаны индексы и переписывание самого запроса. Если данных в плане не хватает, скажи,
какую строку EXPLAIN нужно доснять, и не угадывай.
Проверка перед выдачей: сравни свой запрос с исходным на трёх случаях — у клиента нет заказов,
у клиента заказы только старше 30 дней, у клиента 500 заказов. Если хотя бы в одном наборы строк
расходятся, исправь и напиши, что расходилось.