Что делать если EXPLAIN показывает sequential scan вместо индексного сканирования
Что проверяют
Понимаете ли вы, что планировщик выбирает план по оценке стоимости и статистике, а не по факту существования индекса. И умеете ли читать план вместо угадывания. Формулировка про sequential scan указывает на PostgreSQL, значит отвечать надо в терминах этой СУБД.
Как отвечать
Двигайтесь от плана, а не от индексов:
- снять честный план:
EXPLAIN (ANALYZE, BUFFERS)и сравнить ожидаемое число строк с фактическим. Расхождение на порядок означает проблему статистики, лечитсяANALYZE, а при перекошенном распределении увеличением цели сбора статистики по колонке; - проверить, плох ли Seq Scan вообще: на небольшой таблице и при выборке заметной доли строк последовательное чтение дешевле случайных обращений по индексу, планировщик тут прав;
- посмотреть на условие: функция или приведение типа над колонкой убивают обычный индекс,
lower(email) = $1требует индекса по выражению, поиск по подстроке требует триграммного, а сортировка в запросе должна совпадать с порядком в индексе; - сверить типы параметров: из Go легко отправить значение не того типа, и сравнение уедет с приведением;
- проверить кэш планов: долгоживущие подготовленные выражения в пуле соединений могут перейти на обобщённый план, не учитывающий конкретное значение параметра;
- диагностика:
set enable_seqscan = offв сессии. Если с индексом реально быстрее, дело в стоимостных параметрах, например в цене случайного чтения для SSD.
Где спотыкаются
Считают Seq Scan дефектом всегда и навешивают индексы на все колонки из условий. Индексы замедляют запись, занимают место и всё равно не будут выбраны, когда запрос читает существенную долю таблицы.
Приносят команды из MySQL: SHOW INDEX FROM t и ANALYZE TABLE t. В PostgreSQL это \d t или выборка из pg_indexes, а обновление статистики делается просто командой ANALYZE. Хинтов в ядре нет, они живут в отдельном расширении.
Снимают план на тестовой базе с тысячей строк и переносят вывод на прод. При таком объёме последовательное чтение выигрывает почти всегда, поэтому выводы делают на данных, сравнимых с боевыми, и со свежей статистикой.