ADR 0014: индексы страниц каталога без длительной блокировки записи
Статус: accepted. Дата: 2026-09-23.
Контекст
После ADR 0013 запрос ограничивает выдачу, но без индекса вычисляет SemVer-ключ и сортирует все подходящие строки. На отдельной PostgreSQL 18.4 в Docker, с 100 000 синтетических UPack-версий, прогретым кешем и одним клиентом первая страница из 50 строк занимала около 150–160 мс для каждого из шести вариантов сортировки. EXPLAIN ANALYZE показывал полный просмотр и Sort. Это локальный замер, а не обещание времени ответа под рабочей нагрузкой.
Решение
- Миграция 8 создаёт шесть B-tree индексов по точному порядку
group|name|version × asc|desc, включая равные ключи. Обратный проход по одному индексу не сохраняет нужный порядок всех вторичных полей и может снова сортировать большую группу. - Индексы создаются через
CREATE INDEX CONCURRENTLYвне транзакции. Отдельное соединение миграции имеет лимит SQL-команды 10 минут, в отличие от короткого лимита обычных запросов. Сеансы миграции сериализуются черезpg_try_advisory_lockс ограниченным ожиданием вне SQL-транзакции: блокирующее ожидание advisory lock может образовать взаимную блокировку с concurrent index build. После обрыва повтор использует уже годные индексы, удаляет негодный частичный индекс и продолжает. Версия 8 записывается только после завершения всех шести индексов. - Существующий код не требует новых столбцов. Перед выпуском нового кода запускается
npm run migrate; обычный порядок резервного копирования и остановки процессов сохраняется. Команда может потребовать свободного места для индексов, WAL и временных файлов и ждать длительные транзакции. При превышении лимита её можно запустить повторно после проверки причины.
Измерение и последствия
На том же тестовом наборе после индексации первые страницы занимали около 1–4 мс, а планы использовали Index Scan. Шесть индексов занимали около 60 МБ, таблица пакетов — около 13 МБ; это плата диском и работой при регистрации версии за предсказуемое чтение. Замер не охватывает параллельную запись, холодный кеш, глубокие страницы и рабочее распределение пакетов. Перед промышленным выпуском нужны замеры на репрезентативной копии каталога и наблюдение за размером индексов, временем миграции и WAL.
Уточнение по аудиту 2026-09-24: координация index build использует отдельный session advisory lock 18471/9. Исходный ключ 18471/2 пересекался с reservation-транзакциями uploads и мог останавливать новые загрузки на время построения индекса.