Оптимизатор всегда полностью просматривает таблицу eben, хотя выбирает только 3 строки

У меня есть таблица Foo, которая была создана следующим образом.

CREATE TABLE foo AS SELECT * FROM all_objects;

CREATE INDEX foo_I1 ON foo(owner,object_type,status);
exec dbms_stats.gather_table_stats('hr','foo',method_opt=>'FOR ALL COLUMNS size AUTO');

Я создал индекс по 3 столбцам и запустил запрос, который выглядит как показано ниже.

select  * from foo where status='INVALID';
select  * from foo where status='VALID';

status='VALID' выбирает около 71000 строк в таблице из 71780 строк. он выполняет полное сканирование таблицы. это понятно. но в случае status='INVALID', который выбирает только 3 строки, выполняется полное сканирование таблицы. Это также получает строки A и E очень разные.

ПЛАН: одинаковый для обоих запросов.

SQL_ID gdhy9j91gu9sm, дочерний номер 0

выберите /*+ collect_plan_statistics */ * из foo, где status='VALID'

Plan hash value: 1245013993

------------------------------------------------------------------------------------
| Id  | Operation         | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |      1 |        |     50 |00:00:00.01 |       4 |
|*  1 |  TABLE ACCESS FULL| FOO  |      1 |  71773 |     50 |00:00:00.01 |       4 |
------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("STATUS"='VALID')

Пожалуйста, объясните это поведение. Версия базы данных: 11.2 г оракул.

1 ответ

Решение

Отсутствующая гистограмма, вероятно, вызывает полное сканирование таблицы. Гистограммы обычно создаются только в том случае, если данные искажены и столбец использовался в соответствующем предикате.

Иногда вам нужно выполнить запрос перед сбором статистики, чтобы Oracle знал, что этот столбец достаточно важен, чтобы заслужить гистограмму.

select * from foo where status='INVALID';
exec dbms_stats.gather_table_stats('hr','foo',method_opt=>'FOR ALL COLUMNS size AUTO');

Перезапустите SELECT и теперь он может использовать гистограмму. С помощью гистограммы Oracle знает, что INVALID возвращает небольшое количество строк, и индекс будет полезен:

explain plan for select * from foo where status='INVALID';
select * from table(dbms_xplan.display);

Plan hash value: 1520589999

---------------------------------------------------------------------------------------------
| Id  | Operation                           | Name   | Rows  | Bytes | Cost (%CPU)| Time    |
---------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |        |     1 |   134 |   217   (0)| 00:00:01|
|   1 |  TABLE ACCESS BY INDEX ROWID BATCHED| FOO    |     1 |   134 |   217   (0)| 00:00:01|
|*  2 |   INDEX SKIP SCAN                   | FOO_I1 |     1 |       |   216   (0)| 00:00:01|
---------------------------------------------------------------------------------------------


Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("STATUS"='INVALID')
       filter("STATUS"='INVALID')
Другие вопросы по тегам