Pregunta

Tengo esta mesa:

create table demo (
    key number(10) not null,
    type varchar2(3) not null,
    state varchar2(16) not null,
    ... lots more columns ...
)

y este índice:

create index demo_x04 on demo(key, type, state);

Cuando ejecuto esta consulta

select * from demo where key = 1 and type = '003' and state = 'NEW'

EXPLAIN PLAN muestra que hace un escaneo de mesa completo. Así que dejé caer el índice y lo creé nuevamente. EXPLAIN PLAN Todavía dice escaneo de mesa completo. ¿Como puede ser?

Algunos antecedentes: estos son datos históricos, entonces lo que sucede es que busco una fila con el estado CLEARED e inserte una nueva fila con estado NEW (Además, copio algunos valores de la fila anterior). La antigua fila se actualiza a USED. Entonces la mesa siempre crece. Lo que noté es que la cardinalidad del índice es 0 (a pesar del hecho de que tengo miles de valores diferentes). Después de recrear, la cardinalidad creció, pero al CBO no le gustó más el índice.

A la mañana siguiente, a Oracle de repente le gustó el índice (probablemente durmió sobre él) y comenzó a usarlo, pero no por mucho tiempo. Después de un tiempo, el procesamiento cayó de 50 filas/s a 3 filas/sy vi nuevamente "escaneo de mesa completo". ¿Qué está pasando?

En mi caso, necesito procesar alrededor de un millón de filas. Comprometo los cambios en lotes de ca. 50. ¿Hay algún comando que deba ejecutar después de un compromiso para actualizar/reorger el índice o algo así?

Estoy en Oracle 10G.

Editar] Tengo 969'491 claves distintas en esta tabla, 3 tipos y 3 estados.

¿Fue útil?

Solución

¿Qué sucede si especifica una pista de índice? Prueba esto:

SELECT /*+ INDEX (demo demo_x04) */ * 
  FROM demo 
 WHERE key = 1 
   AND type = '003' 
   AND state = 'NEW';

Parece que lo que sucedió de la noche a la mañana fue que la mesa se analizó. Luego, a medida que ejecutó su procesamiento contra la tabla, se actualizó suficiente del índice para hacer que las estadísticas de Oracle's Table volvieran rancios nuevamente y el optimizador dejó de usar el índice.

Agregue la pista y vea si Explicle Plan le brinda un plan diferente y la consulta funciona mejor.

Ah, y la respuesta de Tony con respecto a analizar la tabla es una buena práctica general, aunque con 10 g de la base de datos es bastante buena al hacer que el mantenimiento de sí mismo en ese sentido. Si su proceso está haciendo muchas actualizaciones, el índice puede pasar rancio rápidamente. Si se ejecuta analizar cuando su proceso comienza a ir en la zanja mejora la situación por un tiempo, entonces sabrá que este es el problema.

Para actualizar las estadísticas de la tabla, use el dmbs_stats.gather_table_stats paquete.

Por ejemplo:

exec dbms_stats.gather_table_stats ('el propietario', 'demo');

Otros consejos

¿Se ha analizado recientemente la tabla? Si Oracle piensa que es muy pequeño, ni siquiera considere usar el índice.

Prueba esto:

select last_analyzed, num_rows 
from user_tables
where table_name = 'DEMO';

Num_rows le dice cuántas filas Oracle cree que contiene la tabla.

"A la mañana siguiente, a Oracle de repente le gustó el índice (probablemente durmió sobre él)" Probablemente un DBMS_STATS se está ejecutando durante la noche.

En general, vería una de las tres razones para un escaneo de tabla completo sobre un índice. La primera es que el optimizador cree que la mesa está vacía, o al menos muy pequeña. Sospecho que este era el problema inicial. En ese caso, sería más rápido escanear una tabla que consta de solo un puñado de bloques en lugar de usar un índice.

El segundo es cuando la consulta es tal que un índice no se puede usar prácticamente.

"select * from demo where key = 1 and type = '003' and state = 'NEW'"

¿En realidad estás usando literales codificados en la consulta? De lo contrario, sus tipos de datos variables pueden ser incorrectos (por ejemplo, la clave es carácter). Eso requeriría que la clave numérica se convierta en carácter para comparar, lo que haría que el índice sea casi inútil.

La tercera razón es donde cree que la consulta procesará una gran proporción de las filas en la tabla. El tipo y el estado parecen cardinalidad bastante baja. ¿Quizás tenga una gran cantidad de un valor específico de 'clave'?

Un comentario sobre el procesamiento que describe: parece que está haciendo un procesamiento de fila por fila con compromisos intermitentes, y le insto a repensar esto si puede. El mecanismo de actualización/inserción bien podría convertirse en una declaración de fusión y todo el conjunto de datos se puede procesar en una sola declaración con una confirmación al final. Esto seguramente sería más rápido y usaría menos recursos que su método actual.

¿El valor de la tecla de columna es siempre 1? Si es así, no estoy seguro de que consultar el índice optimice la consulta, ya que cada fila tendría que ser examinada de todos modos. Si es así, declare el índice sin la columna clave. También podrías probar:

select key, type, state from demo where key = 1 and type = '003' and state = 'NEW'

Lo cual (si mi suposición es correcto) aún necesitaría mirar cada fila, pero cuál podría ir al índice ya que todas las columnas en el conjunto de resultados ahora están cubiertas.

Solo estoy adivinando en base a su declaración de que el índice muestra Cardinality 0.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top