Tengo una tabla con 250K filas en mi base de datos de prueba. (Hay unos pocos cientos de millones en producción, podemos observar el mismo problema allí). La tabla tiene un identificador de cadena nvarchar2 (50), no nulo, con un índice único (no es el PK).
Los identificadores están formados por una primera parte que tiene 8 valores diferentes en mi base de datos de prueba (y alrededor de mil en producción), luego un signo @, y finalmente un número, de 1 a 6 dígitos de largo. Por ejemplo, podría haber 50 mil filas que comienzan con 'ABCD_BGX1741F_2006_13_20110808.xml @', y le siguen 50 mil números diferentes.
Cuando busco una sola fila en función de su identificador, la cardinalidad se estima en 1, el costo es muy bajo y funciona bien. Cuando busco más de una fila con varios identificadores en una expresión IN o una expresión OR, las estimaciones para el índice son completamente incorrectas, por lo que se utiliza una exploración de tabla completa. Si fuerzo el índice con una pista, es muy rápido, el escaneo completo de la tabla en realidad se ejecuta un orden de magnitud más lento (y mucho más lento en la producción). Por lo tanto, es un problema de optimizador.
Como prueba, dupliqué la tabla (en el mismo esquema + espacio de tabla) con exactamente el mismo DDL y exactamente el mismo contenido. Recreé el índice único en la primera tabla para una buena medida, y creé exactamente el mismo índice en la tabla de clonación. Hice un DBMS_STATS.GATHER_SCHEMA_STATS('schemaname',estimate_percent=>100,cascade=>true);
. Incluso puede ver que los nombres de índice son consecutivos. Entonces, la única diferencia entre las dos tablas es que la primera se cargó en orden aleatorio durante un largo período de tiempo, con bloques dispersos en el disco (en un espacio de tabla junto con varias otras tablas grandes), la segunda se cargó como un lote INSERTAR-SELECCIONAR. Aparte de eso, no puedo imaginar ninguna diferencia. (La tabla original se ha reducido desde la última gran eliminación, y no ha habido una sola eliminación después de eso).
Aquí hay planes de consulta para los enfermos y la tabla de clonación (las cadenas debajo del pincel negro son las mismas en toda la imagen, y también debajo del pincel gris):
(En este ejemplo, hay 1867 filas que comienzan con el identificador que está cepillado en negro. Una consulta de 2 filas produce una cardinalidad de 1867 * 2, una consulta de 3 filas produce una cardinalidad de 1867 * 3, etc. No se puede Por casualidad, a Oracle parece no importarle el final de los identificadores).
¿Qué podría causar este comportamiento? Obviamente, sería bastante costoso recrear la mesa en producción.
USER_TABLES: http://i.stack.imgur.com/nDWze.jpg USER_INDEXES: http://i.stack.imgur.com/DG9um.jpg Solo cambié el esquema y el nombre del espacio de tabla. Puede ver que los nombres de tabla e índice son los mismos que en la captura de pantalla del plan de consulta.