Промты для PostgreSQL и MongoDB: 12 сценариев, которые ускоряют запросы, миграции и проектирование схем
Медленный запрос в проде редко бывает загадкой — чаще это отсутствующий индекс, SELECT * в горячем пути или JOIN пяти таблиц там, где хватило бы одного EXPLAIN. Проблема в другом: на диагностику и переписывание уходят часы, а дедлайн миграции уже вчера. Здесь и помогает грамотный промт к LLM: он не заменяет DBA, но превращает рутину «посмотреть план → придумать индекс → проверить на тестовой базе» в один диалог.
Ниже — 12 рабочих сценариев для PostgreSQL и MongoDB, которые я использую сам и подсмотрел у коллег. Каждый промт — это конкретная задача, готовый текст для модели и ожидаемый результат. Я специально разделил их по сложности: базовые (диагностика и генерация), продвинутые (индексы, миграции, агрегации) и экспертные (транзакции, партиционирование, восстановление).
Важная оговорка по достоверности: синтаксис в примерах — настоящий, проверяемый на PostgreSQL 16+ и MongoDB 7.0+. Официальные источники, на которые стоит опираться при работе: документация PostgreSQL, Using EXPLAIN, документация MongoDB и MongoDB Aggregation Pipeline.
Как пользоваться этой подборкой
Каждый промт состоит из трёх частей: Task (что делаем), Prompt (текст для модели) и Example result (что должно получиться). Не вставляйте промт вслепую — добавьте реальную структуру таблиц, версию СУБД и объём данных. Модель без контекста выдаст синтаксически верный, но бесполезный ответ.
| Уровень | Фокус | Сценарии |
|---|---|---|
| Basic | Диагностика, генерация запросов | 1–4 |
| Advanced | Индексы, миграции, агрегации | 5–9 |
| Expert | Транзакции, партиционирование, бэкапы | 10–12 |
Basic: диагностика и генерация
1. Чтение плана запроса через EXPLAIN
Task. Понять, почему запрос медленный, без глубокого знания внутренностей планировщика.
Prompt.
Ты — эксперт по PostgreSQL. Вот вывод EXPLAIN (ANALYZE, BUFFERS) для запроса:
<plan>
...вставьте план...
</plan>
Структура таблиц:
<schema>
...CREATE TABLE ...
</schema>
Объясни простыми словами: 1) где планировщик ошибся в оценке строк (rows vs actual rows),
2) какие узлы самые дорогие, 3) какие индексы стоит создать. Дай конкретный DDL.
Example result. Модель замечает Seq Scan на таблице с 2 млн строк и расхождение оценки (rows=100, actual rows=48000) — классический признак устаревшей статистики. Ответ: ANALYZE orders; плюс CREATE INDEX CONCURRENTLY idx_orders_status_created ON orders (status, created_at);. CONCURRENTLY здесь обязателен — обычный CREATE INDEX блокирует запись в таблицу.
2. Генерация SQL из бизнес-требования
Task. Превратить словесное описание отчёта в корректный SQL.
Prompt.
Напиши SQL для PostgreSQL 16. Задача: для каждого клиента вывести сумму заказов
за последние 90 дней и дату последнего заказа. Ключи: customers.id, orders.customer_id,
orders.total, orders.created_at. Исключи клиентов без заказов. Объясни выбор JOIN.
Example result.
SELECT c.id,
c.name,
COALESCE(SUM(o.total), 0) AS revenue_90d,
MAX(o.created_at) AS last_order_at
FROM customers c
LEFT JOIN orders o
ON o.customer_id = c.id
AND o.created_at >= NOW() - INTERVAL '90 days'
GROUP BY c.id, c.name
HAVING COUNT(o.id) > 0;
Ключевой момент — условие по дате стоит в ON, а не в WHERE. Иначе LEFT JOIN превращается в INNER JOIN и клиенты без заказов исчезают из отчёта.
3. Переписывание запроса без SELECT *
Task. Убрать лишние колонки и ускорить выборку.
Prompt.
Перепиши запрос так, чтобы он не тянул лишние поля и мог использовать index-only scan.
Покажи, какие колонки попадут в индекс. Объясни разницу между Index Scan и Index Only Scan.
Example result. Модель предлагает покрывающий индекс CREATE INDEX idx_orders_cover ON orders (customer_id) INCLUDE (total, created_at);. Разница: Index Scan читает индекс и идёт в heap за данными, Index Only Scan берёт всё из индекса — но только если visibility map актуален (нужен регулярный VACUUM).
4. Генерация MongoDB-запроса по описанию
Task. Найти документы по условиям без ручного подбора операторов.
Prompt.
Напиши запрос для MongoDB 7.0. Коллекция products. Нужно: цена от 100 до 500,
категория в списке ['books','games'], есть поле inStock = true, отсортировать по
rating по убыванию, вернуть только name, price, rating. Покажи проекцию и сортировку.
Example result.
db.products.find(
{ price: { $gte: 100, $lte: 500 },
category: { $in: ["books", "games"] },
inStock: true },
{ _id: 0, name: 1, price: 1, rating: 1 }
).sort({ rating: -1 });
Проекция с _id: 0 экономит трафик. Для сортировки по rating без индекса MongoDB сделает blocking sort в памяти — об этом стоит спросить модель отдельно (см. сценарий 6).
Advanced: индексы, миграции, агрегации
5. Подбор индексов под набор запросов
Task. Не создавать индекс на каждый столбец, а выбрать минимальный набор.
Prompt.
Вот 8 самых частых запросов к таблице events (50 млн строк). Предложи минимальный
набор индексов, избегая избыточных. Для каждого индекса укажи, какие запросы он покрывает,
и оцени стоимость записи. Порядок колонок в составном индексе обоснуй.
Example result. Модель объясняет правило: в составном индексе первым идёт столбец с равенством (=), затем диапазон (>), затем сортировка. Для WHERE user_id = ? AND created_at > ? ORDER BY created_at DESC правильный индекс — (user_id, created_at DESC). Отдельный индекс на created_at избыточен — он уже второй в составном.
6. Проверка MongoDB на blocking sort и collection scan
Task. Убедиться, что запрос использует индекс, а не сканирует коллекцию.
Prompt.
Запрос: db.orders.find({status:'paid'}).sort({created_at:-1}).limit(20)
Как проверить его через explain()? Какие поля вывода говорят о COLLSCAN и SORT stage?
Какой индекс создать и в каком порядке полей?
Example result. Модель советует db.orders.find({status:'paid'}).sort({created_at:-1}).explain("executionStats"). Смотреть на winningPlan.stage: COLLSCAN — плохо, IXSCAN — хорошо, SORT в winningPlan означает сортировку в памяти. Решение — составной индекс { status: 1, created_at: -1 }, где порядок полей повторяет равенство + сортировку.
7. Безопасная миграция с нулевым downtime
Task. Добавить NOT NULL-колонку в большую таблицу, не блокируя прод.
Prompt.
Нужно добавить колонку country text NOT NULL DEFAULT 'unknown' в таблицу users (30 млн строк)
на PostgreSQL 16 без длительной блокировки. Опиши шаги миграции и объясни, почему
ADD COLUMN с DEFAULT в PG 11+ не переписывает таблицу.
Example result. Начиная с PostgreSQL 11 (подтверждено в release notes) ADD COLUMN ... DEFAULT не переписывает таблицу — значение хранится как «missing value». Модель выдаёт:
ALTER TABLE users ADD COLUMN country text NOT NULL DEFAULT 'unknown';
-- без rewrite, но ACCESS EXCLUSIVE берётся на короткое время
Для больших нагрузок совет: выставить lock_timeout, чтобы не застрять в очереди блокировок.
8. Агрегация MongoDB вместо N+1 запросов
Task. Собрать отчёт по заказам с товарами одним pipeline.
Prompt.
Собери aggregation pipeline для MongoDB. Нужно: заказы за последние 30 дней,
развернуть массив items, посчитать выручку по каждому продукту, отсортировать
по выручке, вернуть топ-10. Объясни роль $unwind и $group.
Example result.
db.orders.aggregate([
{ $match: { created_at: { $gte: new Date(Date.now() - 30*24*3600*1000) } } },
{ $unwind: "$items" },
{ $group: { _id: "$items.productId",
revenue: { $sum: { $multiply: ["$items.price", "$items.qty"] } } } },
{ $sort: { revenue: -1 } },
{ $limit: 10 }
]);
$match стоит первым — это позволяет использовать индекс до разворачивания массива. $unwind превращает один документ с массивом в N документов, по одному на элемент.
9. Проектирование схемы MongoDB под доступ
Task. Выбрать между embedding и referencing.
Prompt.
Проектируем MongoDB для блога: посты, комментарии, теги, авторы. Комментарии читаются
всегда вместе с постом, авторы меняются редко. Предложи схему документов и обоснуй
embedding vs referencing. Учти лимит документа 16 МБ.
Example result. Модель предлагает embedding для комментариев (читаются вместе с постом) и referencing для авторов (обновляются независимо). Предупреждает: безлимитный рост массива комментариев упрётся в лимит BSON-документа 16 МБ — тогда нужен паттерн «bucket» или отдельная коллекция. Официальное правило: Data Modeling.
Expert: транзакции, партиционирование, восстановление
10. Корректные транзакции в PostgreSQL
Task. Перевести денежные операции в транзакцию с правильным уровнем изоляции.
Prompt.
Перевод денег между счетами в PostgreSQL. Объясни, почему READ COMMITTED может дать
потерянное обновление при read-modify-write, и покажи два решения: SELECT ... FOR UPDATE
и уровень REPEATABLE READ. Дай код с обработкой ошибок сериализации.
Example result.
BEGIN ISOLATION LEVEL REPEATABLE READ;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;
При REPEATABLE READ конкурентная транзакция получит ошибку could not serialize access (код 40001) — её нужно поймать и повторить. Альтернатива — SELECT ... FOR UPDATE, который блокирует строки до конца транзакции. Официально: Transaction Isolation.
11. Партиционирование большой таблицы
Task. Разбить таблицу логов на партиции по дате.
Prompt.
Таблица logs (200 млн строк, растёт на 5 млн/мес). Нужно партиционирование по месяцу.
Покажи DDL для declarative partitioning в PostgreSQL 16, объясни разницу между
RANGE и LIST, и как партиции влияют на планировщик (partition pruning).
Example result.
CREATE TABLE logs (id bigserial, created_at timestamptz NOT NULL, msg text)
PARTITION BY RANGE (created_at);
CREATE TABLE logs_2026_09 PARTITION OF logs
FOR VALUES FROM ('2026-09-01') TO ('2026-10-01');
Partition pruning отсекает ненужные партиции, если в запросе есть условие по created_at. Важно: партиции и индексы на них создаются отдельно; на PG 11+ есть поддержка уникальных индексов на партиционированных таблицах.
12. План резервного копирования и восстановления
Task. Выбрать стратегию бэкапа и проверить восстановление.
Prompt.
База PostgreSQL 500 ГБ, RPO 15 минут, RTO 1 час. Предложи стратегию: pg_basebackup,
WAL archiving, PITR. Для MongoDB — mongodump vs oplog. Объясни, почему бэкап без
теста восстановления бесполезен.
Example result. Для PostgreSQL: базовый бэкап pg_basebackup + непрерывная архивация WAL даёт point-in-time recovery (PITR) — восстановление на любой момент времени. Для MongoDB: mongodump/mongorestore для логических бэкапов, oplog — для PITR в replica set. Ключевой совет: регулярно прогонять восстановление на отдельном инстансе, иначе бэкап — это лотерея. Источник: PostgreSQL Backup and Restore, MongoDB Backup Methods.
Что действительно экономит время
Три вывода из практики. Первое: самый ценный промт — не «напиши запрос», а «объясни план». Именно EXPLAIN и explain("executionStats") показывают, где реально теряется производительность, а не где кажется. Второе: для схемы важнее вопрос «как читаются данные», а не «как они выглядят логически» — embedding и referencing выбираются под паттерн доступа, а не под красоту модели. Третье: миграции и бэкапы — это про блокировки и тесты восстановления, а не про синтаксис.
Попробуйте взять два-три промта из подборки на ближайшей задаче: сначала получите ответ модели, затем проверьте его на тестовой базе и сверьте с официальной документацией. LLM отлично ускоряет черновик — финальное решение всё равно за вами и вашим EXPLAIN.
Comments