Практикум: партиционирование существующей таблицы в окно обслуживания¶
Переводим таблицу events сервиса аналитики на месячные партиции. Обновлённый пример использует окно обслуживания: запросы приложения к данным приостановлены на время перехода. Диагностические запросы специально проверяют промежуточные состояния. Непрерывная работа приложения во время переноса здесь не обещается.
Нужны Docker и uv. Выполните команды из этого каталога:
uv run --no-project --python 3.13 --with-requirements requirements.txt python migrate_lab.py
uv run --no-project --python 3.13 --with-requirements requirements.txt python batch_boundary_lab.py
migrate_lab.py создаёт 615 исторических событий за июль–сентябрь 2026 года, одно событие от роли приложения и двадцать заметок. Полные исходные строки сохраняются для сравнения после переноса. Каждая строка PASS появляется после проверки результата на PostgreSQL.
| Проверка | Ожидаемый результат |
|---|---|
Партиционирование по created_at со старым PRIMARY KEY (id) |
SQLSTATE 0A000 |
| Удаление первичного ключа, на который ссылается внешний | SQLSTATE 2BP01 |
| Переключение при активной читающей транзакции | SQLSTATE 55P03; rollback сохраняет таблицу, внешний ключ и строки |
| Создание июльской партиции, пока июльские строки ещё в DEFAULT | SQLSTATE 23514 |
| Перенос одной порции из 100 строк | Родитель видит 516 строк, отдельная июльская таблица хранит 100; вместе они в точности совпадают с исходными 616 |
| Новый toolkit и продолжение переноса | Все месяцы подключены, все сохранённые строки видны через родителя |
| Старое представление до обновления запроса | После переноса из старой таблицы оно насчитывает ноль строк |
| Восстановление составного внешнего ключа после переноса | Без времени: 23502; неверная пара: 23503 |
| Восстановление прав, представления и владельца sequence; удаление пустой DEFAULT | Исходная вставка события от роли приложения проходит, sequence выдаёт следующий id |
| Ключи и планы запросов | Одинаковая пара запрещена; тот же id с другим временем разрешён; июльский запрос читает одну партицию |
| Запись вне диапазонов без DEFAULT | SQLSTATE 23514 |
batch_boundary_lab.py проверяет границу порции: если лимит порций кончился сразу после порции, которая опустошила месяц, таблица месяца остаётся неподключённой и родитель не видит её строк. plan() показывает это как unattached_rows, а следующий вызов partition_data подключает таблицу (pg-partsmith 1.5.1 мог оставить такой месяц скрытым и при этом вернуть complete=True; в 1.7.0 это исправили). Затем тест сравнивает все 100 исходных строк через родителя.
Функции из статьи находятся в migration_flow.py, а исходная схема с представлением и ролью приложения в schema.sql. SQL вставки события не меняется, но при создании заметки теперь нужны и event_id, и event_created_at. Эти шаги запускают только после паузы приложения и завершения его активных операций; готового HTTP-режима обслуживания в практикуме нет.
Версии Python-зависимостей закреплены: pg-partsmith 1.8.0, SQLAlchemy 2.0.54, asyncpg 0.31.0, pydantic 2.13.5 и testcontainers 4.15.0. Контейнер postgres:17-alpine удаляется при выходе. Фиксированные даты и небольшой набор данных нужны для проверки корректности, не для оценки длительности блокировок в продакшене. Автоматическое удаление старых партиций во время переноса не запускается.