SQL Performance Tuning Prompts for PostgreSQL and MongoDB Teams Without a Dedicated DBA

PostgreSQL без DBA: 11 промтов, которые переписывают медленные запросы, индексы и миграции за вас

Половина инцидентов в проде начинается одинаково: «страница грузится 8 секунд, посмотри, что там с базой». У вас нет выделенного DBA, зато есть EXPLAIN ANALYZE, медленный лог и LLM, которая читает план запроса быстрее, чем вы успеваете открыть pgAdmin. По данным опроса Stack Overflow Developer Survey, PostgreSQL стабильно держится в топ-3 самых используемых баз данных, и большинство команд работают с ней без профильного администратора.

Ниже — 11 промтов, которые я и команды вокруг реально прогоняют через AI-агента на asibiont.com. Каждый — с проблемой, промтом, ожидаемым результатом и выводом. Синтаксис, команды и системные представления (pg_stat_statements, pg_stat_user_indexes, EXPLAIN (ANALYZE, BUFFERS)) — настоящие, из официальной документации PostgreSQL.

1. Разбор EXPLAIN ANALYZE на человеческий

Проблема: план на 200 строк, глаза разбегаются. Промт:

Ты — PostgreSQL DBA. Вот вывод EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT) для запроса.
Объясни: 1) где теряется время, 2) какие узлы дают наибольший actual time,
3) какой тип join использован и почему, 4) что переписать. Отвечай таблицей.

<plan>...</plan>
<query>SELECT ...</query>

Результат: таблица «узел → rows actual vs estimated → вердикт». Ключевой сигнал — расхождение rows estimated и actual в разы: значит статистика устарела, нужен ANALYZE. Когда применять: первый шаг любого разбора медленного запроса.

2. Переписывание JOIN-монстра

Проблема: запрос с 6 JOIN и подзапросами в WHERE. Промт: просим заменить коррелированные подзапросы на EXISTS/LATERAL, вынести фильтры раньше, проверить порядок соединений. Результат: часто LATERAL с LIMIT 1 вместо JOIN + DISTINCT убирает сортировку миллионов строк. Вывод: не трогайте work_mem вслепую — сначала перепишите план.

3. Генерация индекса под конкретный запрос

Проблема: sequential scan на 5 млн строк. Промт:

Даны запрос и план. Предложи индексы: B-tree, составной, partial или covering.
Укажи точный CREATE INDEX CONCURRENTLY и объясни порядок колонок.

Результат: составной индекс (tenant_id, created_at DESC) вместо двух одиночных, плюс partial WHERE status = 'active'. Важно: создавайте через CREATE INDEX CONCURRENTLY, чтобы не блокировать запись.

4. Поиск неиспользуемых индексов

Проблема: индекс режет вставки, но не читается. Промт: просим SQL по pg_stat_user_indexes и pg_stat_user_tables:

SELECT relname, indexrelname, idx_scan
FROM pg_stat_user_indexes WHERE idx_scan = 0;

Результат: список кандидатов на DROP INDEX CONCURRENTLY. Вывод: сбрасывайте статистику (pg_stat_reset()) перед замером, иначе цифры за всю историю.

5. Безопасная миграция с блокировками

Проблема: ALTER TABLE ... ADD COLUMN NOT NULL DEFAULT вешал таблицу. Промт: просим переписать в паттерн expand-contract: добавить колонку nullable, бэкфилл батчами, затем SET NOT NULL через NOT VALID constraint + VALIDATE CONSTRAINT. Результат: нулевой downtime. Вывод: в PostgreSQL 11+ ADD COLUMN ... DEFAULT не переписывает таблицу, но SET NOT NULL и смена типа — переписывают.

6. Партиционирование большой таблицы

Проблема: таблица логов на 500 ГБ. Промт: просим стратегию PARTITION BY RANGE (created_at) по месяцам, скрипт создания партиций, автоматизацию через pg_partman. Результат: планировщик читает только релевантные партиции (partition pruning). Вывод: проверьте, что запросы фильтруют по ключу партиционирования, иначе pruning не сработает.

7. Убийство N+1 в ORM

Проблема: Django/SQLAlchemy шлёт 200 запросов на страницу. Промт: просим найти N+1, заменить на select_related/joinedload или prefetch_related, показать до/после с django-debug-toolbar. Результат: 200 → 2 запроса. Вывод: логируйте pg_stat_statements — повторяющиеся одинаковые запросы это и есть N+1.

8. Оптимизация пагинации на больших смещениях

Проблема: OFFSET 100000 тормозит. Промт: просим keyset-пагинацию (WHERE id > :last_id ORDER BY id LIMIT 20). Результат: O(1) вместо O(offset). Вывод: курсорная пагинация требует стабильной сортировки по уникальному ключу.

9. Борьба с блокировками и дедлоками

Промт: просим запросы к pg_locks, pg_stat_activity и pg_blocking_pids() для поиска блокирующей транзакции, плюс рекомендации по коротким транзакциям и единому порядку блокировок. Результат: находим idle in transaction, который держит lock. Вывод: ставьте idle_in_transaction_session_timeout.

10. MongoDB: агрегация вместо N запросов

Проблема: в MongoDB цикл find() в приложении. Промт: просим переписать в $lookup + $match + $group, проверить через explain('executionStats'), что totalDocsExamined близко к nReturned. Результат: один pipeline вместо тысяч round-trip. Вывод: индекс под $match обязателен, иначе collection scan.

11. Аудит запроса перед продом

Промт: «Проверь этот SQL на: SQL-инъекции, отсутствие индексов, implicit casts, функции в WHERE по индексируемой колонке, SELECT *». Результат: чек-лист замечаний. Вывод: встраивайте этот промт в code review — дешевле, чем ловить на проде.

Промт Экономит
EXPLAIN-разбор часы дебага
Индексы секунды на запрос
Миграции downtime
N+1 нагрузку на БД

Половина этих задач раньше упиралась в «нужен DBA». Сегодня достаточно научить AI-агента читать планы и системные представления — остальное он сгенерирует с точным синтаксисом. Начните с первых трёх промтов на своём медленном запросе: через час у вас будет и план, и индекс, и объяснение, почему это работает. Дальше — миграции и партиционирование.

← All posts

Comments