Какие индексы разумно ставить на числовые и строковые поля в базе данных
Что проверяют
Понимаете ли вы, какой оператор в запросе обслуживает какой индекс, и что ORM делает с индексами сама. Для Python-разработчика это обычно PostgreSQL и Django или SQLAlchemy. Следом часто спрашивают, почему icontains тормозит, хотя индекс есть.
Как отвечать
Числовые поля почти всегда закрываются B-tree: он работает на =, диапазонах и ORDER BY. Кандидаты: внешние ключи, created_at, суммы в фильтрах. Сам PostgreSQL внешние ключи не индексирует, Django для ForeignKey создаёт индекс по умолчанию, в SQLAlchemy нужно явно указать index=True.
Со строками вариантов больше:
- равенство и уникальность: B-tree, для email или логина уникальный.
unique=Trueуже создаёт индекс,db_index=Trueрядом не нужен; - без учёта регистра: индекс по выражению, в Django
models.Index(Lower("email"), name="email_lower"), и в запросе тот жеLower; - префикс
LIKE 'abc%': B-tree помогает только с классомvarchar_pattern_opsили коллациейC. Django на PostgreSQL дляCharFieldсdb_index=Trueсам создаёт второй индекс с суффиксом_like; - подстрока
'%abc%': только триграммы, расширениеpg_trgmи GIN с классомgin_trgm_ops, в Django черезGinIndexиOpClass; - поиск по словам:
SearchVectorи GIN поtsvector; - флаги и статусы: частичный индекс
models.Index(fields=["status"], condition=Q(status="new"), name="status_new").
Хэш-индекс в PostgreSQL надёжен с 10-й версии, но выигрыш над B-tree обычно мал, а диапазонов и сортировки он не умеет. На большой таблице индекс добавляют через AddIndexConcurrently в миграции с atomic = False.
Где спотыкаются
Ставят db_index=True на BooleanField. При двух значениях планировщик всё равно читает таблицу, а запись дорожает.
Строят триграммный индекс по самой колонке и ждут, что его подхватит icontains. Django оборачивает колонку в UPPER(...), поэтому индекс нужен по тому же выражению: OpClass(Upper("name"), name="gin_trgm_ops").
Проверяют индекс на тестовой базе в тысячу строк. На маленькой таблице планировщик честно выбирает Seq Scan, и выводы о пользе индекса получаются ложными.