Для каких колонок почти всегда нужно создавать индексы?
Что проверяют
Умеете ли вы выбирать индексы от запросов, а не по списку «все колонки из WHERE». Для Java-разработчика следом почти всегда идёт вопрос про внешние ключи в JPA и про то, как проверить, что индекс действительно используется.
Как отвечать
Короткий список «почти всегда»:
- первичный ключ: индекс создаётся автоматически вместе с ограничением, отдельно его не объявляют;
- уникальные колонки:
UNIQUEтоже создаёт индекс сам. Но только если ограничение объявлено: колонкаemailбез него остаётся без индекса; - внешние ключи: главный пункт. MySQL (InnoDB) индексирует их сам, PostgreSQL нет. Без индекса на
orders.customer_idкаждыйJOINи каждое удаление клиента сканирует всю таблицу заказов. Для@ManyToOneс@JoinColumnиндекс объявляют явно: в миграции Flyway или Liquibase либо через@Table(indexes = @Index(columnList = "customer_id")); - частые фильтры с высокой селективностью:
user_id, номер заказа, внешний идентификатор; - сортировка с лимитом: запрос
ORDER BY created_at DESC LIMIT 20с индексом поcreated_atчитает двадцать строк вместо сортировки всей таблицы.
Остальное решается по факту. Медленные запросы видны в pg_stat_statements или в логе медленных запросов, план смотрят через EXPLAIN (ANALYZE, BUFFERS), а неиспользуемые индексы находят по нулевому idx_scan в pg_stat_user_indexes. Составной индекс строят под конкретный запрос: сначала колонки с равенством, потом с диапазоном.
Где спотыкаются
Индексируют всё подряд, включая колонки из ORDER BY и GROUP BY без лимита. Каждый индекс замедляет запись, а планировщик большую часть не возьмёт.
Вешают индекс на колонку с двумя-тремя значениями вроде status или is_deleted. Полезнее частичный индекс WHERE is_deleted = false или составной вместе с селективной колонкой.
Рассчитывают, что Hibernate сам всё сделает. ddl-auto в проде не используют, индексы на внешние ключи за вас никто не продумает, их пишут в миграциях руками.