Почему индекс по created_at не используется
Вопрос
Есть B-tree индекс orders_created_at_idx по created_at. Почему в плане нет обращения к нему?
Gather (cost=1000.00..16199.67 rows=5000 width=32) (actual time=18.035..56.183 rows=2880 loops=1)
Workers Planned: 2
Workers Launched: 2
-> Parallel Seq Scan on orders (cost=0.00..14699.67 rows=2083 width=32) (actual time=20.416..43.039 rows=960 loops=3)
Filter: (date((created_at AT TIME ZONE 'UTC'::text)) = '2024-03-01'::date)
Rows Removed by Filter: 332373
Planning Time: 0.477 ms
Execution Time: 56.398 ms
Попробуйте сами
Выберите вариант, и откроется разбор.
Показать ответ и разбор
Коротко
Варианты ответа
- Колонка завёрнута в функцию, а индекс хранит сами значенияправильный ответ
- Параллельные воркеры не читают индексы, и выбран параллельный план
- Под условие попадает больше половины таблицы, Seq Scan дешевле
- Индекс по
timestamptzне подходит для сравнения с типомdate
Разбор
Индекс применим, когда условие имеет вид «индексированное выражение, оператор, значение». Здесь в условии date(created_at AT TIME ZONE 'UTC'), которого в индексе нет, и планировщику остаётся только читать всё и считать функцию для каждой строки (Rows Removed by Filter). Решения два: переписать фильтр диапазоном created_at >= '2024-03-01' AND created_at < '2024-03-02' (в нужной зоне) или создать индекс по тому же выражению. Параллельные планы умеют и Parallel Index Scan. Под фильтр попадает 2880 строк из миллиона, так что дело не в селективности. Сравнение timestamptz с date индекс тоже поддерживает: значение приводится к типу колонки.
Ответьте сами, а не прочитайте
В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.
Предыдущий вопрос
Перепиши фильтр ts::date под индекс по времени
Следующий вопрос
Index Only Scan с большим Heap Fetches