SQL, миграции, схемы: Vibe Codex для баз данных
База — это место, где «попробуем и посмотрим» обходится дороже, чем где бы то ни было. Поэтому ассистент тут особенно полезен — если знает, что не трогать.
Работа с базами делится на две стороны: проектная (схемы, индексы, миграции) и оперативная (тяжёлые запросы, локи, дедлоки). На обеих Vibe Codex полезен, но в разных ролях.
Разбор медленного запроса
Запрос на 12 секунд в проде — классика жанра. Vibe Codex читает EXPLAIN ANALYZE и переводит на человеческий: где именно теряется время, что виновато — план, статистика или железо.
$ psql -c "EXPLAIN (ANALYZE, BUFFERS) SELECT ..." \
| vibe-codex sql-explain
[opus] План:
- Seq Scan по orders, потому что Postgres решил, что индекс
idx_orders_user не выгоден (statistics target=10, для
user_id=42 кардинальность недооценена — 8 строк по плану,
1.7 млн по факту).
[opus] Что попробовать:
1) ANALYZE orders; (дёшево, иногда лечит)
2) ALTER TABLE orders ALTER COLUMN user_id SET STATISTICS 1000;
3) Покрывающий индекс по (user_id, status) INCLUDE (total).
Проектирование схемы
Vibe Codex умеет работать в режиме «обсуждение перед миграцией». Опишите бизнес-сущность — получите DDL с натуральными ограничениями, индексами и FK.
$ vibe-codex schema "сущность Refund: \
привязан к Order, сумма частичная или полная, \
статус (REQUESTED, APPROVED, REJECTED, PAID), \
кто запросил, кто подтвердил, аудит-логи."
[plan] 1 file: db/schema/refunds.sql
CREATE TABLE refunds (
id bigserial PRIMARY KEY,
order_id bigint NOT NULL REFERENCES orders(id),
amount_cents bigint NOT NULL CHECK (amount_cents > 0),
status text NOT NULL CHECK (status IN
('REQUESTED','APPROVED','REJECTED','PAID')),
requested_by bigint NOT NULL REFERENCES users(id),
approved_by bigint REFERENCES users(id),
created_at timestamptz NOT NULL DEFAULT now(),
approved_at timestamptz,
CONSTRAINT refund_amount_le_order
CHECK (amount_cents <= (SELECT total_cents FROM orders WHERE id = order_id))
);
CREATE INDEX refunds_order_idx ON refunds (order_id);
CREATE INDEX refunds_status_idx ON refunds (status) WHERE status IN ('REQUESTED','APPROVED');
Заметьте частичный индекс по «горячим» статусам — модель помнит про этот приём и применяет без напоминаний.
Миграции без downtime
Это критическая зона. ALTER TABLE с тяжёлой блокировкой может уложить прод. Vibe Codex знает паттерны zero-downtime для Postgres и предлагает их по умолчанию.
$ vibe-codex migrate "добавь NOT NULL колонку currency \
в orders, дефолт RUB"
[opus] Прямой ALTER ... SET DEFAULT 'RUB' NOT NULL на 50 млн
строк блокирует таблицу. Делаем в 3 шага:
V01__currency_add_nullable.sql:
ALTER TABLE orders ADD COLUMN currency text;
V02__currency_backfill.sql:
-- запускать частями, без транзакции на всё
-- batch SQL прилагается отдельно.
V03__currency_not_null.sql:
ALTER TABLE orders
ALTER COLUMN currency SET DEFAULT 'RUB';
-- проверить через VALIDATE CONSTRAINT,
-- затем SET NOT NULL.
«Хорошая миграция — это та, которую можно остановить на середине без последствий для прода».
JSONB, partial indexes, deferrable constraints
Vibe Codex знает «острые» углы Postgres. Например, не использует оператор ? для JSONB внутри JPA @Query — это крашит Hibernate. Вместо этого предложит jsonb_extract_path или jsonb_path_exists.
Sequence vs. UUID — обсуждение, а не предписание
Когда вы спрашиваете «UUID или bigserial», ассистент не выдаёт «UUID лучше». Он спрашивает контекст: распределённая ли система, нужна ли сортируемость по времени, важен ли размер ключа.
$ vibe-codex "что выбрать для PK orders: bigserial или uuid?"
[opus] Зависит:
- Если orders создаются только в одной мастер-БД и нужна
сортируемость — bigserial выигрывает (16 байт против 8,
меньше TOAST, лучше cache locality).
- Если есть оффлайн-клиенты или несколько источников записи —
ULID/UUIDv7 даст уникальность без координации и сохранит
приблизительную сортируемость.
- Скажите контекст — выдам решение, а не предпочтение.
Дедлоки и lock waits
Логи Postgres с дедлоками — это всегда «кто кого». Vibe Codex читает их и переводит в граф: какой запрос держит, какой ждёт, как переупорядочить.
$ tail -n 200 /var/log/postgresql/postgres.log \
| vibe-codex pg-deadlock
[opus] Дедлок №34: между UPDATE orders SET ... WHERE id IN (1,2)
и UPDATE orders SET ... WHERE id IN (2,1).
[opus] Виновата ORM: не сортирует id перед батч-апдейтом.
Fix: добавить ORDER BY id в IN-список или
сделать UPDATE через одиночные запросы.
Чего ассистент не делает
- Не запускает миграцию на prod. Генерирует SQL и команду — нажимаете вы.
- Не правит данные напрямую. UPDATE без WHERE — табу.
- Не предлагает
DROP TABLEбез явной явной просьбы. - Не путает MySQL и Postgres — читает
application.ymlилиknexfile.
База — это инструмент, в котором уважение к «как было раньше» окупается каждый день. Vibe Codex это уважение разделяет: предлагает то, что зайдёт на ревью к опытному DBA, и не пытается «оптимизировать всё подряд».
Готов попробовать?
brew tap xrouter-chat/tap && brew install vibe-codex — и за 30 секунд ты в деле.
Поставить Vibe Codex →