Dmitriy Kononov
Обсудим задачуСвязаться

Новости и разборы

Как менять схему базы без сюрпризов. Ветки Supabase, pg-delta и миллионы SQLite у Cloudflare

Ветки и pg-delta у Supabase, D1 на SQLite у Cloudflare, sequence в Neki и pgrecon для Oracle. Как я меняю структуру базы в работающей системе без сломанных отчётов.

Четыре заметки за неделю про структуру баз данных. Supabase показал, как создаётся ветка-копия проекта и как теперь строятся миграции на pg-delta. Cloudflare рассказал, как D1 держит миллионы баз SQLite. PlanetScale объяснил, почему sequence в шардированном Postgres нельзя отдать шарду. А в новостях PostgreSQL анонсировали pgrecon, инструмент оценки переезда с Oracle. Общая тема одна: изменение структуры данных должно быть предсказуемым. Для бизнеса это звучит так: добавили в заказ новое поле, и ни один отчёт и ни одна интеграция не сломались.

Что вышло

Supabase 15 октября разобрал, как новая ветка получает конфигурацию, миграции и функции. Ветка это отдельный проект, и при создании параллельно идут три части: копирование настроек с основного проекта, миграции и развёртывание Edge Functions; медианное время готовности около 20 секунд. Каждый файл миграции выполняется как одна транзакция. У каждого шага есть состояние: RUNNING, EXITED, PAUSED или DEAD, так что при сбое видно, что успело отработать.

13 октября Supabase описал Declarative Schemas 2.0 на pg-delta, которые показали 2 октября на Supabase Select. Схема хранится в SQL-файлах, а CLI сам пишет миграцию. pg-delta поднимает две временные базы, в одну загружает файлы схемы, в другую проигрывает историю миграций, сравнивает их по системному каталогу и упорядочивает результат по графу зависимостей. В дифф теперь входят RLS-политики, гранты, домены, партиции и объекты расширений, а разрушающие вызовы CLI помечает отдельно.

PlanetScale 14 октября опубликовал заметку о sequence и других volatile-выражениях в Neki, их шардированном Postgres. Есть класс выражений router-only: now() на разных шардах даст разное время из-за дрейфа часов, поэтому его считают на маршрутизаторе один раз на запрос. Sequence по той же причине требует центра: гарантию, что номер не повторится, нельзя разделить между шардами.

Cloudflare 13 октября рассказал, как D1 масштабируется до миллионов баз. D1 это их бессерверная база на SQLite. По их цифрам на 8 октября 2026 года число живых баз выросло в 15 раз за год и в 65 раз за два, а число активных в день в 18 раз за год. Принципы, которые они называют: проектировать каждый процесс с расчётом на сбой и повторный запуск без побочного эффекта, не ставить централизованных компонентов на путь запроса и проверять систему нагрузкой, близкой к реальной.

22 октября в новостях PostgreSQL появился pgrecon 0.7.3, инструмент оценки переезда с Oracle на PostgreSQL под лицензией Apache-2.0. Работает офлайн: скрипт только для чтения делает дамп, инструмент строит по нему инвентарь, прогоняет 80 правил и выдаёт диапазон человеко-дней. Всё, что перенести нельзя, попадает в отдельный отчёт остатка.

Пример: прокат добавляет детское кресло

Компания по аренде автомобилей ведёт брони в Google Таблице и добавляет колонку «плата за детское кресло». Интеграция с CRM ждёт прежний набор колонок, приложение для менеджеров про новое поле не знает, а отчёт по выручке суммирует не то. Это миграция схемы без инструментов и без ветки, где её можно проверить. В ЮАР я с этого начинал: первая задача была связать AmoCRM с Google Таблицей, чтобы в ней обновлялись стоимость обслуживания, пробег и плата за детское кресло, а затем сопоставить поля приложения на FlutterFlow с AmoCRM и настроить синхронизацию для выбранных полей. Схема это договор между системами, и менять её нужно так, чтобы все стороны узнали об этом заранее.

Как это устроено у меня

Сервис «Кофе вместе» написан на React и TypeScript и работает в рантайме Cloudflare Workers с D1 API поверх локальной базы SQLite в Docker volume, на общем сервере с 2 ГБ памяти. Сайт kononov.dev тоже на SQLite.

Первый из принципов Cloudflare, повторный запуск без побочного эффекта, у меня работает в «Кофе вместе»: журнал импорта из старой Google Таблицы связывает заказ с номером исходной строки, поэтому повторная загрузка не создаёт дубликатов, а изменённая строка показывается как конфликт. Рядом правило, которое я держу сам: неудачный шаг не портит рабочие данные. Каталог синхронизируется с оптовым API Tasty Coffee по расписанию, и неудачная попытка не стирает опубликованный каталог.

В PDR-компании в США в 2023 году я предложил перейти с Google Таблиц на SQL-базу ради скорости и единого формата данных. Идею поддержали, и после перехода на MariaDB мы подключали новые сервисы один за другим. Любую миграцию лучше сначала прогнать на копии базы и только потом выпускать. Ветки Supabase, pg-delta и pgrecon у себя не запускал и сужу по описаниям.

Что я бы сделал

Держать миграции файлами в репозитории с номером версии и таблицей применённых версий в самой базе, как это делает Supabase.

Прогонять каждую миграцию на вчерашней копии рабочей базы вместе с приложением и отчётами.

Менять поля в два шага: сначала добавить новое и перевести на него все системы, удалять старое отдельным выпуском, когда список потребителей пуст.

Читать дифф, который написал инструмент, глазами, особенно всё, что помечено как разрушающее.

Если переезд между разными СУБД, начинать с инвентаря и списка того, что перенести нельзя, по образцу pgrecon.

О том, почему состояние системы должно жить в одном месте, есть статья о сервере как ядре системы. Сервис из этого обзора: «Кофе вместе». Три решения в базе, о которых жалеют позже, в обзоре о каскадном удалении, шардах и репликах, платформы против своего сервера в обзоре о бэкендах на Vercel, Fly и Supabase, радиус поражения обновлений в обзоре об инструменте Netflix и TypeScript 7.1. Посредников перед обновлением базы я проверял раньше. Направления: инфраструктура и DevOps и внутренние системы. Если вам предстоит менять структуру данных в работающей системе, расскажите, что меняется и кто этими данными пользуется. Обсудить задачу.