2010-02-02 2 views
12

У меня был запрос, где индекс не был использован, когда я думал, что это может быть, поэтому я воспроизводил его из любопытства:Почему индекс не используется для этого запроса?

Создать test_table с 1.000.000 строк (10 различных значений в col, 500 байт данных в some_data).

CREATE TABLE test_table AS (
    SELECT MOD(ROWNUM,10) col, LPAD('x', 500, 'x') some_data 
    FROM dual 
    CONNECT BY ROWNUM <= 1000000 
); 

Создание индекса и собирать статистику таблицы:

CREATE INDEX test_index ON test_table (col); 

EXEC dbms_stats.gather_table_stats('MY_SCHEMA', 'TEST_TABLE'); 

Try, чтобы получить различные значения col и COUNT:

EXPLAIN PLAN FOR 
    SELECT col, COUNT(*) 
    FROM test_table 
    GROUP BY col; 

--------------------------------------------------------------------------------- 
| Id | Operation   | Name  | Rows | Bytes | Cost (%CPU)| Time 
--------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT |   | 10 | 30 | 15816 (1)| 00:03:10 
| 1 | HASH GROUP BY  |   | 10 | 30 | 15816 (1)| 00:03:10 
| 2 | TABLE ACCESS FULL| TEST_TABLE | 994K| 2914K| 15755 (1)| 00:03:10 
--------------------------------------------------------------------------------- 

Индекс не используется, обеспечивая намек делает не измените это.

Я думаю, индекс не может быть использован в этом случае, но почему?

+1

Использование индекса не будет в состоянии предотвратить полную проверку, так что это на самом деле не дает никаких преимуществ. – recursive

+0

@recursive: Похоже, это правда, но почему это не полное сканирование индекса, предпочитаемого над полным сканированием таблицы? –

+0

Если вы не нашли здесь решение, попробуйте asktom.oracle.com (что было очень полезно для меня в прошлом). –

ответ

5

Я побежал оригинальный материал Питера и воспроизводится его результаты. Я тогда применяется предложение DCP в ...

SQL> alter table test_table modify col not null; 

Table altered. 

SQL> EXEC dbms_stats.gather_table_stats(user, 'TEST_TABLE' , cascade=>true) 

PL/SQL procedure successfully completed. 

SQL> EXPLAIN PLAN FOR 
    2 SELECT col, COUNT(*) 
    3 FROM test_table 
    4 GROUP BY col; 

Explained. 

SQL> select * from table(dbms_xplan.display) 
    2/

PLAN_TABLE_OUTPUT 
------------------------------------------------------------------------------------ 
Plan hash value: 2099921975 

------------------------------------------------------------------------------------ 
| Id | Operation    | Name  | Rows | Bytes | Cost (%CPU)| Time  | 
------------------------------------------------------------------------------------ 
| 0 | SELECT STATEMENT  |   | 10 | 30 | 574 (9)| 00:00:07 | 
| 1 | HASH GROUP BY  |   | 10 | 30 | 574 (9)| 00:00:07 | 
| 2 | INDEX FAST FULL SCAN| TEST_INDEX | 1000K| 2929K| 532 (2)| 00:00:07 | 
------------------------------------------------------------------------------------ 

9 rows selected. 

SQL> 

Причина, это важно, потому, что значения NULL, не включаются в нормальный индекс B-дерева, но GROUP BY должна включать NULL в качестве группировки «значение» в Ваш запрос. Сообщая оптимизатору, что нет нулей в col, можно использовать гораздо более эффективный индекс (я получал прошедшее время почти 3,55 секунды с FTS). Это классический пример того, как метаданные могут влиять на оптимизатор.

Кстати, это, очевидно, база данных 10g или 11g, поскольку вместо алгоритма SORT (GROUP BY) используется алгоритм HASH GROUP BY.

+0

@ APC - Это dcp, а не Dep :) – dcp

+1

@ dcp - извините, мне нужно есть больше моркови. Я исправил свой цвет. – APC

+0

Нет проблем. Эй, по крайней мере, вы не написали «Dope» :). – dcp

13

ОБНОВЛЕНИЕ: Попробуйте сделать столбец столбца NOT NULL. Именно по этой причине он не использует индекс. Когда это не пусто, вот план.

SELECT STATEMENT, GOAL = ALL_ROWS   69 10 30 
        HASH GROUP BY   69 10 30 
INDEX FAST FULL SCAN SANDBOX TEST_INDEX 56 98072 294216 

Если оптимизатор определяет, что это более эффективно не использовать индекс (возможно, из-за перезаписи запроса), то он не будет. Рекомендации оптимизатора - вот что, а именно, подсказки, чтобы сообщить Oracle о том, что вы должны использовать как. Вы можете думать о них как о предложениях. Но если оптимизатор определяет, что лучше не использовать индекс (опять же, как результат перезаписи запроса, например), тогда этого не произойдет.

Обратитесь к этой ссылке: http://download.oracle.com/docs/cd/B19306_01/server.102/b14211/hintsref.htm «Указание один из этих намеков вызывает оптимизатор выбрать указанный путь доступа, только если путь доступа доступен на основе существования индекса или кластера и синтаксических конструкций в SQL Если подсказка указывает недоступный путь доступа, оптимизатор игнорирует ее ».

Поскольку вы используете операцию count (*), оптимизатор определил, что более эффективно просто сканировать всю таблицу и хеш вместо использования вашего индекса.

Вот еще один удобный ссылка на намеки: http://www.dba-oracle.com/t_hint_ignored.htm

+0

В данных запроса не выводится ни одна из данных из таблицы, просто 'col' и' count (*) '. Весь результат может быть получен путем сканирования индекса. Не кажется ли логичным, что быстрее сканировать индекс вместо таблицы (даже если он должен делать полное сканирование в любом случае)? Индекс меньше .. –

+0

@ dcp: Я знаю, как работают подсказки, мне было любопытно, почему индекс не использовался на первом месте. –

+0

@Sam: Да, это то, что я тоже думал ... –

10

Вы забыли это действительно важную информацию: COL не является нулевым

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

SQL> ALTER TABLE test_table MODIFY (col NOT NULL); 

Table altered 
SQL> EXPLAIN PLAN FOR 
    2 SELECT col, COUNT(*) FROM test_table GROUP BY col; 

Explained 
SQL> SELECT * FROM table(dbms_xplan.display); 

PLAN_TABLE_OUTPUT 
-------------------------------------------------------------------------------- 
Plan hash value: 1077170955 
-------------------------------------------------------------------------------- 
| Id | Operation   | Name  | Rows | Bytes | Cost (%CPU)| Time 
-------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT  |   | 10 | 30 | 1954 (1)| 00:00:2 
| 1 | SORT GROUP BY NOSORT|   | 10 | 30 | 1954 (1)| 00:00:2 
| 2 | INDEX FULL SCAN | TEST_INDEX | 976K| 2861K| 1954 (1)| 00:00:2 
-------------------------------------------------------------------------------- 
0

индекс битовой карты будет делать, а

 
Execution Plan 
---------------------------------------------------------- 
Plan hash value: 2200191467 

--------------------------------------------------------------------------------- 
| Id | Operation   | Name  | Rows | Bytes | Cost (%CPU)| Time  | 
--------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT |   | 10 | 30 | 15983 (2)| 00:03:12 | 
| 1 | HASH GROUP BY  |   | 10 | 30 | 15983 (2)| 00:03:12 | 
| 2 | TABLE ACCESS FULL| TEST_TABLE | 1013K| 2968K| 15825 (1)| 00:03:10 | 
--------------------------------------------------------------------------------- 

SQL> create bitmap index test_index on test_table(col); 

Index created. 

SQL> EXEC dbms_stats.gather_table_stats('MY_SCHEMA', 'TEST_TABLE'); 

PL/SQL procedure successfully completed. 

SQL> SELECT col, COUNT(*) 
    2 FROM test_table 
    3 GROUP BY col 
    4/

Execution Plan 
---------------------------------------------------------- 
Plan hash value: 238193838 

--------------------------------------------------------------------------------------- 
| Id | Operation    | Name  | Rows | Bytes | Cost (%CPU)| Time  | 
--------------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT   |   | 10 | 30 | 286 (0)| 00:00:04 | 
| 1 | SORT GROUP BY NOSORT |   | 10 | 30 | 286 (0)| 00:00:04 | 
| 2 | BITMAP CONVERSION COUNT|   | 1010K| 2961K| 286 (0)| 00:00:04 | 
| 3 | BITMAP INDEX FULL SCAN| TEST_INDEX |  |  |   |   | 
--------------------------------------------------------------------------------------- 

+0

Индексы растровых изображений подходят только для ограниченного диапазона таблиц. Если наша таблица подвержена множеству вставок, обновлений или удалений, то стоимость поддержания индекса может быть слишком большой. – APC

Смежные вопросы