Ответ
Оптимизатор СУБД может выбрать полное сканирование таблицы (FULL TABLE SCAN) вместо использования индекса в следующих основных случаях:
-
Низкая селективность условия: Если условие
WHEREохватывает большую часть таблицы (например, >15-20% строк). Сканирование по индексу с последующими обращениями к таблице (TABLE ACCESS BY INDEX ROWID) становится дороже, чем прямое последовательное чтение.-- Индекс по is_active вряд ли будет использован, если 90% строк active SELECT * FROM users WHERE is_active = TRUE; -
Отсутствие подходящего префикса индекса: Для составного индекса
(A, B)запрос с фильтром только поBне сможет его использовать эффективно. -
Использование функций или модификаторов столбца: Индекс по
created_atне будет использован, если применить к нему функцию.-- Не использует индекс по created_at SELECT * FROM logs WHERE DATE(created_at) = '2023-10-01'; -- Решение: создать функциональный индекс или переписать запрос SELECT * FROM logs WHERE created_at >= '2023-10-01' AND created_at < '2023-10-02'; -
Неактуальная статистика: Если статистика по таблице устарела, оптимизатор может ошибиться в оценке стоимости.
-
Подсказка оптимизатору или маленькая таблица: Для очень маленьких таблиц сканирование всегда дешевле. Также можно явно указать
/*+ FULL(table_name) */.
Как проверить? Используйте EXPLAIN (или EXPLAIN ANALYZE):
EXPLAIN ANALYZE
SELECT * FROM large_table WHERE low_selectivity_column = 'common_value';
-- В плане выполнения будет видно "Seq Scan" вместо "Index Scan"