Главная  /  Статьи  /  Database

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 через одиночные запросы.

Чего ассистент не делает

База — это инструмент, в котором уважение к «как было раньше» окупается каждый день. Vibe Codex это уважение разделяет: предлагает то, что зайдёт на ревью к опытному DBA, и не пытается «оптимизировать всё подряд».

Готов попробовать?

brew tap xrouter-chat/tap && brew install vibe-codex — и за 30 секунд ты в деле.

Поставить Vibe Codex →