Индексы, которые не используются
Индексы обычно только добавляют: где-то запрос притормозил — повесили индекс, стало быстрее. Удаляет их редко кто. В итоге за пару лет накапливается слой, о котором никто не помнит.
Решил посчитать. Запрос, который показывает, сколько раз индексом реально пользовались:
SELECT schemaname, relname AS table_name, indexrelname AS index_name,
idx_scan AS scans,
pg_size_pretty(pg_relation_size(indexrelid)) AS size
FROM pg_stat_user_indexes
WHERE idx_scan = 0
AND indexrelid NOT IN (SELECT conindid FROM pg_constraint)
ORDER BY pg_relation_size(indexrelid) DESC;
У себя обнаружил, что примерно треть индексов не прочитана ни разу за полгода. При этом каждый честно замедляет вставку, занимает диск и раздувает бэкапы.
Прежде чем удалять
Пара оговорок, о которые легко споткнуться:
-
Проверьте период статистики.
idx_scanсчитается с последнегоpg_stat_reset()или рестарта. Если статистику сбросили неделю назад — квартальный отчёт в неё не попал. -
Не трогайте уникальные индексы. Они могут не использоваться для чтения,
но обеспечивают ограничение целостности. В запросе выше они исключены через
pg_constraint. - Учтите реплики. Статистика локальна для каждого узла: на мастере индекс может простаивать, а на реплике его активно читают отчёты.
Обратная сторона: чего не хватает
Заодно полезно посмотреть, где идут последовательные сканы по крупным таблицам:
SELECT relname, seq_scan, idx_scan,
pg_size_pretty(pg_relation_size(relid)) AS size
FROM pg_stat_user_tables
WHERE seq_scan > idx_scan AND pg_relation_size(relid) > 100e6
ORDER BY seq_scan DESC;
Если большая таблица регулярно читается целиком — либо не хватает индекса,
либо запрос написан так, что существующий не применяется
(функция над колонкой, несовпадение типов, LIKE '%...').
Удалять индексы стоит по одному и с паузой. Если что-то замедлится — сразу понятно, какой вернуть.