Будет ли индекс работать если порядок условий в запросе отличается от порядка полей в индексе
Что проверяют
Знаете ли вы, что работу индекса определяет набор колонок в условии, а не порядок, в котором они написаны в WHERE. Подвох в том, что многие уверенно отвечают «нет». Следом обычно спрашивают про правило левого префикса и про запрос только по второй колонке.
Как отвечать
Короткий ответ: да, будет. WHERE b = ? AND a = ? и WHERE a = ? AND b = ? для оптимизатора одно и то же, AND коммутативен, и планировщик PostgreSQL, MySQL или Oracle сам сопоставит условия с колонками индекса (a, b). Дальше покажите, что на самом деле важно:
- левый префикс: индекс
(a, b, c)работает для условий поa, поaиb, по всем трём. Для запроса только поbобычный поиск по B-tree невозможен. Оговорка: в MySQL 8.0 и PostgreSQL 18 есть skip scan для случая, когда в первой колонке мало различных значений, но проектировать под него не стоит; - равенство раньше диапазона: при
a > ? AND b = ?индекс(a, b)найдёт начало диапазона поa, аbбудет проверяться на каждой записи внутри него. Индекс(b, a)для такого запроса лучше; - сортировка:
ORDER BYберёт порядок из индекса, только если его колонки идут в индексе следом за колонками с равенством; - проверка: гадать не нужно,
EXPLAIN(в PostgreSQLEXPLAIN ANALYZE) показывает, какой индекс выбран.
Для Java-стека свяжите это с практикой. В Spring Data findByStatusAndCreatedAt и findByCreatedAtAndStatus дают один и тот же план. Индекс в JPA объявляется через @Table(indexes = @Index(columnList = "status, created_at")).
Где спотыкаются
Отвечают, что порядок условий в запросе важен, и предлагают переставлять их под индекс. Это миф, оптимизатор переставляет их сам.
Вешают отдельный индекс на каждую колонку вместо составного. База умеет их комбинировать (bitmap в PostgreSQL, index merge в MySQL), но это обычно медленнее одного индекса (a, b).
Теряют индекс на несовпадении типов, хотя порядок полей идеален. Классика для SQL Server: JDBC-драйвер по умолчанию шлёт строки как NVARCHAR, колонка объявлена VARCHAR, и из-за неявного приведения вместо поиска по индексу может получиться сканирование. Лечится параметром sendStringParametersAsUnicode=false.