Как учитывать разницу в объеме данных при тестировании с индексами
Что проверяют
Понимаете ли вы, что на маленькой базе проверка индекса ничего не доказывает: планировщик выбирает план по статистике, и на тысяче строк он честно пойдёт полным сканированием. Следом обычно спрашивают, где взять реалистичные данные и как понять, что индекс действительно используется.
Как отвечать
- объём и распределение: важно не только число строк, но и форма данных: селективность колонок, перекосы вроде «90% заказов в одном статусе», размер строк. На равномерных синтетических данных план будет не таким, как в проде;
- генерация: в PostgreSQL удобно
INSERT ... SELECTизgenerate_seriesили загрузка черезCOPY, после чего нуженANALYZE, иначе у планировщика может не оказаться свежей статистики. Альтернатива: обезличенная копия прода; - смотреть план, а не секундомер:
EXPLAIN (ANALYZE, BUFFERS)показывает, какой узел выбран (Index Scan,Bitmap Heap Scan,Seq Scan), сколько строк ожидалось и сколько пришло, сколько страниц прочитано из кэша и с диска; - окружение в Java: интеграционные тесты через Testcontainers на той же СУБД и версии, что в проде. H2 даже в режиме совместимости не повторяет планировщик PostgreSQL, выводы о производительности на нём неверны;
- запросы из приложения: Hibernate генерирует не всегда тот SQL, который вы ожидаете. Логируйте фактические запросы и снимайте план именно с них, а на живой базе опирайтесь на
pg_stat_statements.
Отдельно стоит сказать о записи: каждый индекс замедляет вставку и обновление, поэтому прогон на полном объёме проверяет и их, особенно пакетные загрузки.
Где спотыкаются
Делают вывод «индекс не помогает» на десятке тысяч строк, где полное сканирование и правда дешевле.
Заливают данные и сразу меряют без ANALYZE, а потом удивляются, что план в тесте и в проде разный.
Проверяют запрос в psql с подставленными литералами, а приложение шлёт его через PreparedStatement. После нескольких выполнений PostgreSQL может перейти на обобщённый план, который не учитывает конкретные значения, и на перекошенных данных он оказывается хуже.