2009-04-06 28 views
15

Tenemos Oracle 10g y necesitamos consultar 1 tabla (sin uniones) y filtrar filas donde 1 de las columnas es nula. Cuando hacemos esto - DONDE OurColumn IS NOT NULL - obtenemos un escaneo de tabla completo en una mesa muy grande - MAL MALO MALO. La columna tiene un índice pero se ignora en esta instancia. ¿Hay alguna solución para esto?Oracle 10g - optimizar DONDE NO ES NULO

Gracias

Respuesta

20

El optimizador cree que la exploración de tabla completa será mejor.

Si solo hay unas pocas filas NULL, el optimizador es correcto.

Si está absolutamente seguro de que el índice de acceso será más rápido (es decir, tiene más de 75% filas con col1 IS NULL), luego insinuar su consulta:

SELECT /*+ INDEX (t index_name_on_col1) */ 
     * 
FROM mytable t 
WHERE col1 IS NOT NULL 

Por qué 75%?

Dado que el uso para recuperar los valores que no están cubiertos por el índice implica una oculta unirse en ROWID, que cuesta unos 4 veces más que el recorrido de tabla.

Si el rango de índice incluye más de 25% de filas, el escaneo de tabla suele ser más rápido.

Como se menciona por Tony Andrews, el factor de agrupamiento es el método más preciso para medir este valor, pero 25% sigue siendo una buena regla empírica.

+1

Quassnoi, ¿de dónde sacas ese 75%? Si hay un millón de filas y solo una es nula, ¿por qué el uso de un índice en esas columnas sería más lento que una exploración de tabla? – tpdi

+1

Porque el índice implica una unión oculta en ROWID, que cuesta aproximadamente 4 veces más que la exploración de tabla. Si la selectividad del índice es inferior al 25%, la exploración de la tabla suele ser más rápida. – Quassnoi

+2

En una exploración de tabla completa, simplemente itera sobre todas las filas de la tabla; si realiza un escaneo de índice, primero debe leer el índice y luego leer la tabla. Desde cierto punto, el costo de leer un índice es más alto que simplemente leer toda la tabla. – andri

2

Si usted está haciendo un select *, entonces tendría sentido hacer un recorrido de tabla en lugar de utilizar el índice. Si sabe en qué columnas está interesado, puede crear un índice cubierto con esas columnas más el que está aplicando la condición IS NOT NULL.

0

Cree un índice en esa columna.

Para asegurarse de que se utiliza el índice, debe estar en el índice y otras columnas en el where.

ocdecio respondió:

Si usted está haciendo un select *, entonces tendría sentido hacer una mesa de estudio en lugar de utilizar el índice.

Eso no es estrictamente cierto; se usará un índice si hay un índice que se ajuste a su cláusula where, y el optimizador de consultas decida que usar ese índice sería más rápido que hacer una exploración de tabla. Si no hay índice, o no hay índice adecuado, solo entonces se debe realizar un escaneo de tabla.

+0

Excelentes comentarios en Select * Sin embargo, para aclarar - nunca utilizamos SELECT * por otras razones - siempre incluimos nuestra lista de columnas en las cláusulas SELECT. –

15

El optimizador tomará su decisión en función del costo relativo de la exploración de tabla completa y el uso del índice. Esto se reduce principalmente a cuántos bloques tendrán que leerse para satisfacer la consulta. La regla de 25%/75% mencionada en otra respuesta es simplista: en algunos casos, una exploración completa de la tabla tendrá sentido incluso para obtener el 1% de las filas, es decir, si esas filas se distribuyen en muchos bloques.

Por ejemplo, considere la siguiente tabla:

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  

Como se puede ver, sólo aproximadamente el 1% de las filas de T1 tiene un object_id no nulo.Pero debido a la forma en que construí la tabla, estas 861 filas se distribuirán más o menos uniformemente alrededor de la mesa. Por lo tanto, la consulta:

select * from t1 where object_id is not null; 

es probable que visitar casi todos los bloques de la T1 para obtener los datos, incluso si el optimizador utiliza el índice. ¡Tiene sentido entonces prescindir del índice y realizar un escaneo completo de la tabla!

Una estadística clave para ayudar a identificar esta situación es el factor de índice de agrupación:

SQL> select clustering_factor from user_indexes where index_name='T1_IDX'; 

CLUSTERING_FACTOR 
----------------- 
       460 

Este valor 460 es bastante alto (en comparación con las 861 filas en el índice), y sugiere que un escaneo completo de tabla se ser usado. Ver this DBAZine article on clustering factors.

1

Puede depender del tipo de índice que tenga sobre la mesa.

La mayoría de los índices B-tree do no almacenar entradas nulas. Los índices de mapa de bits hacen almacenar entradas nulas.

lo tanto, si usted tiene:

seleccionar * de mitabla donde micolumna es nulo

y tiene un índice de árbol B de serie en mycolumn, la consulta no puede use el índice ya que el "nulo" no está en el índice.

(Si el índice está en contra de varias columnas, y una de las columnas indizadas no es nulo, entonces habrá una entrada en el índice.)

+1

La pregunta se refería a una búsqueda 'is not null', not' is null'. – KajMagnus

+0

Sin embargo, es información útil –

0

También vale la pena comprobar si las estadísticas de Oracle en la tabla son hasta fecha. Es posible que no sepa que una exploración de tabla completa será más lenta.

0

Oracle do valores nulos no indexa en absoluto en índices (b) de árboles regulares, por lo que no se puede usar ni se puede' t forzar la base de datos Oracle para usarlo.

BR

+0

Esta pregunta es sobre 'no es nulo'. Todos los valores relevantes estarán en el índice. –

0

El uso de sugerencias debe hacerse solo como una solución alternativa en lugar de una solución.

Como se menciona en otras respuestas, el valor nulo no está disponible en los índices B-TREE.

Dado que sabe que tiene en su mayoría valores nulos en esta columna, ¿podría reemplazar el valor nulo por un rango, por ejemplo?

Eso realmente depende de su columna y la naturaleza de sus datos, pero por lo general, si su columna es un tipo de fecha, por ejemplo:

where mydatecolumn is not null se puede traducir en una regla que dice: Quiero todas las filas que tienen una fecha.

A continuación, puede sin duda hacer esto: donde mydatecolumn < = sysdate (en Oracle)

Esto devolverá todas las filas con una fecha y ommit valores nulos, mientras que aprovechando el índice en esa columna sin utilizar ningún consejos.

Cuestiones relacionadas