Модель предлагает индекс Postgres: база решает, создавать или нет

Три режима вместо «да, создай индекс»: LLM генерирует гипотезу, Postgres замеряет план, транзакция откатывается. Для соло-разработчика с моделью в цикле оптимизации опаснее правдоподобный совет без выбора планировщиком, чем глупый. В разборе Remdore показывает, как обернуть каждое предложение модели в автоматическую аттестацию без слепого CREATE INDEX в прод.
Три режима вместо «доверяй модели»
LLM готов предложить индекс под любой показанный SQL. Remdore не принял это на веру и собрал контур агентной верификации: модель предложила, среда проверила, изменения не остались в базе.
Цикл в утилите pg-index-referee выглядит так:
BEGIN → CREATE INDEX → ANALYZE → EXPLAIN (ANALYZE, BUFFERS) → ROLLBACK
Индекс «никогда не существовал» снаружи транзакции. Флаг --apply только печатает прошедшие проверку индексы и не создаёт их на живой БД. Для агента, который тащит SQL-патчи в PR, это снимает риск «разумно выглядящего» индекса без плана.
Согласие двух LLM между собой ≠ верификация: consensus мог бы привести к одинаковым, но отвергнутым индексам в прод.
Что видит LLM и что проверяет Postgres
На каждый запрос модель получает схему, список существующих индексов и EXPLAIN (ANALYZE, BUFFERS) этого запроса. Может предложить до трёх CREATE INDEX. Дословные system/user prompt Remdore не публиковал; зафиксирован только pipeline propose → referee.
Postgres выступает судьёй по двум критериям, не только по миллисекундам:
- Запрос заметно ускорился.
- Планировщик реально выбрал новый индекс: обход узлов
EXPLAIN, сборIndex Name, проверка наличия созданного индекса.
Пример ложноположительного по часам: индекс дал 17% ускорения (14,2 ms → 12,19 ms), но index used: False, и такой индекс отбрасывается. CREATE INDEX CONCURRENTLY снимается: внутри транзакции rollback важнее keyword.
Замер берётся как быстрейший из пяти повторов EXPLAIN, не среднее. После создания индекса обязателен ANALYZE: без него планировщик решает на устаревшей статистике. На expression index lower(kind) при 1,2M строк estimate 6 000 vs actual 200 000 rows, типичная ловушка для «быстрого» совета из чата.
Цифры бенчмарка: consensus ≠ verification
Эксперимент на Postgres 18, 3 таблицы, ~1,5M строк (основная events: 1,2M, 104 MB). 8 «обычных» SQL-запросов; на каждый до 3 предложений индекса, затем referee.
Remdore прогнал 9 моделей через OpenAI-compatible endpoint DigitalOcean Serverless Inference, не один выбранный LLM, а сравнение на одном наборе запросов. Суммарно 151 предложенный индекс: все построены, измерены и откатаны. Стоимость inference около 5,5 центов.
«Four in ten did not survive» совпадает с keep rate 58–67% verified по моделям, то есть ~33–42% предложений не проходят двойную проверку. 6 из 8 запросов улучшались у всех моделей, которые ответили на все восемь. 2 запроса с агрегатами и join по большой доле таблицы не улучшились ни у одной модели: на них предложено 41 индекс, ни один не прошёл проверку. Postgres здесь даёт ответ, которого модели не дают: «у запроса нет index problem».
| model | proposed | verified | queries improved |
|---|---|---|---|
| openai-gpt-oss-20b | 20 | 12 | 6/8 |
| openai-gpt-oss-120b | 21 | 13 | 6/8 |
| router:software-engineering | 13 | 9 | 4/8 (3 blank) |
| glm-5.3-flash | 12 | 7 | 6/8 |
| gemma-4-31B-it | 13 | 8 | 6/8 |
| mistral-3-14B | 24 | 16 | 6/8 |
| deepseek-3.2 | 24 | 15 | 6/8 |
| deepseek-v4-pro | 17 | 10 | 6/8 |
| nemotron-3-ultra-550b | 7 | 7 | 5/8 (3 blank) |
Разброс цены 18× ($/M in от 0,050 до 0,900), а доля verified в узком коридоре. Формального параллельного ревью DBA нет; шесть улучшенных запросов не удивили бы того, кто «tuned Postgres by hand», по оценке Remdore.
Reasoning-модели съедали output budget: cap 1200 tokens давал пустой ответ при полной оплате; поднятие до 3000 исправило blank responses. У Nemotron 3 из 8 пустых ответов из‑за reasoning, укладывающегося в budget, отдельный класс сбоя агентного цикла.
Как повторить harness локально
Репозиторий oceanforge/pg-index-referee на GitHub, лицензия MIT:
pip install -e .
pg-index-referee --queries examples/queries.sql --apply
Воспроизведение: examples/setup.sql (детерминированный seed), examples/queries.sql. Перед и после серии замеров снимок pg_indexes; при расхождении утилита не выходит «тихо».
Ограничения harness, которые стоит учесть при интеграции с агентом:
- Prepared statements: создание индекса инвалидирует планы; harness гоняет literal
EXPLAIN, не prepared path production. ANALYZEв транзакции критичен для expression indexes.- Отдельная test DB: Remdore один раз deadlock'нул эксперимент, прогнав test suite с
DROP TABLEна той же БД.
Для соло-workflow с LLM в IDE смысл не в «найти лучшую модель», а вынести правило в окружение: любое предложение индекса от модели проходит тот же referee, прежде чем попадёт в миграцию. База единственный арбитр, который не согласуется ради красивого diff.
Источники
- Remdore — I let a model suggest Postgres indexes, then made the database mark its work (Dev.to, 2026-09-09)
- Репозиторий утилиты: oceanforge/pg-index-referee