Оптимизатор думает, что полное сканирование таблицы будет лучше.
Если существуют только некоторые NULL
строки, оптимизатор является правильным.
Если Вы абсолютно уверены, что индексный доступ будет быстрее (то есть, у Вас есть больше, чем 75%
строки с col1 IS NULL
), затем подскажите свой запрос:
SELECT /*+ INDEX (t index_name_on_col1) */
*
FROM mytable t
WHERE col1 IS NOT NULL
Почему 75%
?
Поскольку использование INDEX SCAN
получать значения, не покрытые индексом, подразумевает скрытое соединение на ROWID
, который стоит о 4
времена так же как сканирование таблицы.
Если индексный диапазон включает больше, чем 25%
из строк сканирование таблицы обычно быстрее.
Как упомянуто Tony Andrews
, кластеризация фактора является более точным методом для измерения этого значения, но 25%
все еще хорошее эмпирическое правило.
Если бы Вы делаете выбор *, то имело бы смысл делать сканирование таблицы вместо того, чтобы использовать индекс. Если Вы знаете, какими столбцами Вы интересуетесь, Вы могли создать покрытый индекс с теми colums плюс тот, который Вы применяете, условие NOT NULL.
Оптимизатор примет свое решение на основе относительной стоимости полного сканирования таблицы и использования индекса. Это главным образом сводится, сколько блоков должно будет быть считано для удовлетворения запроса. 25%/75 эмпирических правил %, упомянутых в другом ответе, упрощенны: в некоторых случаях полное сканирование таблицы будет иметь смысл даже получать 1% строк - т.е. если те строки, оказывается, распространены вокруг многих блоков.
Например, рассмотрите эту таблицу:
SQL> create table t1 as select object_id, object_name from all_objects;
Table created.
SQL> alter table t1 modify object_id null;
Table altered.
SQL> update t1 set object_id = null
2 where mod(object_id,100) != 0
3 /
84558 rows updated.
SQL> analyze table t1 compute statistics;
Table analyzed.
SQL> select count(*) from t1 where object_id is not null;
COUNT(*)
----------
861
Как Вы видите, только приблизительно 1% строк в T1 имеет непустой указатель object_id. Но из-за пути я создал таблицу, эта 861 строка будет распространена более или менее равномерно вокруг таблицы. Поэтому запрос:
select * from t1 where object_id is not null;
вероятно, посетил бы почти каждый блок в T1 для получения данных, даже если бы оптимизатор использовал индекс. Имеет смысл затем обходиться без индекса и идти для полного сканирования таблицы!
Ключевая статистическая величина, чтобы помочь определить эту ситуацию является индексным фактором кластеризации:
SQL> select clustering_factor from user_indexes where index_name='T1_IDX';
CLUSTERING_FACTOR
-----------------
460
Это значение 460 довольно высоко (по сравнению с этой 861 строкой в индексе) и предполагает, что будет использоваться полное сканирование таблицы. См. эту статью DBAZine о кластеризирующихся факторах.
Это может зависеть от типа индекса, который у вас есть в таблице.
Большинство индексов B-дерева не хранят пустые записи. Растровые индексы делают хранят нулевые записи.
Итак, если у вас есть:
выберите * из mytable где mycolumn равно нулю
, и у вас есть стандартный индекс B-дерева для mycolumn
, тогда запрос не может использовать индекс, так как «ноль» отсутствует в index.
(Если индекс относится к нескольким столбцам, и один из индексированных столбцов не равен NULL, то в индексе будет запись.)
Создайте индекс на том столбце.
Для проверки индекс используется, это должно быть на индексе и других столбцах в где.
ocdecio отвечают:
Если бы Вы делаете выбор *, то имело бы смысл делать сканирование таблицы вместо того, чтобы использовать индекс.
Это не строго верно; индекс будет использоваться, если будет индекс, который соответствует Вашему, где пункт и оптимизатор запросов решают использование, что индекс был бы быстрее, чем выполнение сканирования таблицы. Если нет никакого индекса или никакого подходящего индекса, только затем должен сканирование таблицы делаться.
Также стоит проверить, актуальна ли статистика Oracle в таблице. Возможно, он не знает, что полное сканирование таблицы будет медленнее.
См. http://www.oracloid.com/2006/05 / using-index-for-is-null /
Если ваш индекс находится в одном поле, он НЕ будет использоваться. Попробуйте добавить в индекс фиктивное поле или константу:
create index tind on t(field_to_index, 1);