Могут ли индексы замедлять операции и в каких случаях
Что проверяют
Понимаете ли вы цену индекса на уровне своего ORM, а не только на уровне учебника. Часто следом спрашивают, как вы добавите индекс на таблицу в десятки миллионов строк так, чтобы не остановить прод.
Как отвечать
Индекс замедляет всё, что меняет данные, а иногда и чтение. Разберите случаи:
- массовая запись:
bulk_createв Django илиinsert()в SQLAlchemy обновляют каждый индекс на каждую строку. Для разовой загрузки больших объёмов быстрее снять вторичные индексы, залить данные черезCOPYи построить индексы заново; - лишние индексы от ORM: Django сам создаёт индекс на каждом
ForeignKey. Если у модели естьUniqueConstraint(fields=["user", "created"]), отдельный индекс поuserдублирует его левую часть, и его отключают черезdb_index=False; - индекс на меняющихся полях: индекс по
updated_atили счётчику база обновляет при каждомsave(), а в PostgreSQL он ещё и отключает HOT-обновления; - неудачный план: на низкоселективной колонке или при устаревшей статистике планировщик берёт индекс там, где последовательное чтение быстрее. Помогают
ANALYZEи пересмотр самого индекса; - построение индекса: обычный
CREATE INDEXблокирует запись в таблицу.
Для последнего пункта назовите инструменты: в Django операция AddIndexConcurrently из django.contrib.postgres.operations в миграции с atomic = False, в Alembic op.create_index(..., postgresql_concurrently=True) внутри autocommit_block(). Для анализа: EXPLAIN ANALYZE, pg_stat_user_indexes и django-debug-toolbar, чтобы видеть реальные запросы ORM.
Частичный индекс models.Index(fields=[...], condition=Q(is_active=True)) часто снимает спор «индекс или запись»: он меньше и затрагивает только нужные строки.
Где спотыкаются
Ставят db_index=True на каждое поле, по которому когда-то фильтровали в админке, и потом удивляются медленным импортам.
Не знают, что ORM делает под капотом: не видят автоматических индексов на внешних ключах и уникальных полях и заводят дубли руками.
Добавляют индекс обычной миграцией на большую таблицу в рабочее время. Миграция висит на блокировке, очередь запросов растёт, сервис отвечает таймаутами.