2010-02-02 25 views
12

tuve una consulta en los que no se utilizó un índice cuando pensé que podría ser, por lo que la reprodujo por curiosidad:¿Por qué no se utiliza el índice para esta consulta?

Crear un test_table con 1.000.000 filas (10 valores distintos en col, 500 bytes de datos en some_data).

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

Crear un índice y recopilar estadísticas de tabla:

CREATE INDEX test_index ON test_table (col); 

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

Intentar obtener valores distintos de col y la 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 
--------------------------------------------------------------------------------- 

No se utiliza el índice, proporcionando la pista hace no cambiar esto

Supongo que el índice no se puede utilizar en este caso, pero ¿por qué?

+1

Utilizando el índice no sería capaz de evitar que un análisis completo, por lo que realmente no proporciona ningún beneficio. – recursive

+0

@recursive: Parece que es cierto, pero ¿por qué no se prefiere una exploración completa en el índice sobre la exploración de tabla completa? –

+0

Si no encuentra la solución aquí, puede probar asktom.oracle.com (que me ha sido muy útil en el pasado). –

Respuesta

5

me corrieron material original de Pedro y reproducen sus resultados. Luego aplica la sugerencia de 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> 

La razón por la que esto es importante, se debe a que los valores NULL no están incluidos en un índice normal de árbol B, pero el GROUP BY tiene que incluir NULL como un "valor" en la agrupación su consulta. Al decirle al optimizador que no hay valores NULL en col, es libre de usar el índice mucho más eficiente (obtenía un tiempo transcurrido de casi 3.55 segundos con el FTS). Este es un ejemplo clásico de cómo los metadatos pueden influir en el optimizador.

Por cierto, esto es obviamente una base de datos 10g u 11g, porque usa el algoritmo HASH GROUP BY, en lugar del algoritmo SORT (GROUP BY) más antiguo.

+0

@APC - Es dcp, no Dep :) – dcp

+1

@dcp - lo siento, tengo que comer más zanahorias. He corregido mi bloomer. – APC

+0

No hay problema. Oye, al menos no escribiste "Dope" :). – dcp

13

ACTUALIZACIÓN: Intente hacer que la columna COL NO sea NULA. Esa es la razón por la que no usa el índice. Cuando no es nulo, aquí está el plan.

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

Si el optimizador determina que es más eficiente no utilizar el índice (quizás debido a la reescritura de la consulta), entonces no lo hará. Las sugerencias del optimizador son solo eso, es decir, sugerencias para decirle a Oracle un índice que como usar. Puedes pensar en ellos como sugerencias. Pero si el optimizador determina que es mejor no usar el índice (de nuevo, como resultado de la reescritura de la consulta, por ejemplo), entonces no va a funcionar.

se refieren a este enlace: http://download.oracle.com/docs/cd/B19306_01/server.102/b14211/hintsref.htm "Especificación de una de estas pistas hace que el optimizador de elegir el camino de acceso especificado sólo si la ruta de acceso está disponible en base a la existencia de un índice o cluster y en las construcciones sintácticas del SQL declaración. Si una pista especifica una ruta de acceso no disponible, el optimizador la ignora ".

Dado que está ejecutando una operación de conteo (*), el optimizador ha determinado que es más eficiente escanear toda la tabla y el hash en lugar de usar su índice.

Aquí hay otro enlace a mano en consejos: http://www.dba-oracle.com/t_hint_ignored.htm

+0

Ninguno de los datos de la tabla se muestra en la consulta, solo 'col' y' count (*) '. El resultado completo podría producirse escaneando el índice. ¿No parece lógico que sea más rápido escanear el índice en lugar de la tabla (incluso si tiene que hacer un escaneo completo de cualquier forma)? El índice es más pequeño. –

+0

@dcp: Sé cómo funcionan las sugerencias. Tenía curiosidad de por qué el índice no se usó en primer lugar. –

+0

@Sam: Sí, eso es lo que yo también pensaba ... –

10

se le olvidó esta información realmente importante: COL no es nulo

Si la columna es anulable, el índice no se puede utilizar porque puede haber filas no indexados.

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

índice de mapa de bits hará así

 
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

Los índices de mapa de bits son adecuados solo para un rango limitado de tablas. Si nuestra tabla está sujeta a muchas inserciones, actualizaciones o eliminaciones, entonces el costo de mantener el índice puede ser demasiado. – APC

Cuestiones relacionadas