Кейс: индекс молчал, потому что типы не совпадали
Таблица orders, миллионы строк, индекс на external_id. Запрос с фильтром по external_id шёл секундами — план показывал Seq Scan, индекс висел мёртвым грузом.
external_id в базе — varchar, потому что приходит из внешней системы и иногда содержит буквы. Код передавал параметр как Long, JDBC-драйвер приводил его к строке на своей стороне без проблем — запрос выполнялся, результат был верный. Проблема была в соседнем отчётном запросе: аналитика сравнивала external_id с числовым литералом без кавычек, и Postgres неявно приводил к сравнению через CAST на стороне колонки, а не литерала.
-- медленно: cast применяется -- к каждой строке колонки SELECT * FROM orders WHERE external_id = 12345;
-- быстро: тип совпадает, -- индекс используется SELECT * FROM orders WHERE external_id = '12345';
EXPLAIN ANALYZE сразу показал разницу: в первом случае Seq Scan on orders с фильтром по CAST(external_id AS bigint), во втором — Index Scan using orders_external_id_idx. Planner не станет использовать индекс, если для сравнения нужно привести тип самой индексируемой колонки — это работает только для выражений, под которые есть отдельный expression index.
Тип параметра в запросе — не деталь для компилятора, а часть плана выполнения. Один незакавыченный литерал превращает Index Scan в Seq Scan на таблице в миллионы строк.
Тренажёр: 600 вопросов, мок с таймером, план повторов
senior·base — что спрашивают на самом деле
В этом посте были ссылки, но мы их удалили по правилам Сетки