2010-07-01 20 views
5

Tengo una base de datos Oracle 10.2.0.3, y una consulta como esta:Oracle explicar el plan estimaciones de cardinalidad incorrecto para un rango de exploración de índice

select count(a.id) 
from LARGE_PARTITIONED_TABLE a 
join SMALL_NONPARTITIONED_TABLE b on a.key1 = b.key1 and a.key2 = b.key2 
where b.id = 1000 

Tabla LARGE_PARTITIONED_TABLE (a) tiene unos 5 millones de filas, y se reparte por una columna no presente en la consulta. La tabla SMALL_NONPARTITIONED_TABLE (b) no está particionada y contiene aproximadamente 10000 filas.

Las estadísticas están actualizadas, y hay histogramas de altura equilibrada en las columnas clave1 y clave2 de la tabla a.

La tabla a tiene una clave principal y un índice único global sin particiones en las columnas clave1, clave2, clave3, clave4 y clave5.

explicar el plan para la consulta mostrará los siguientes resultados:

--------------------------------------------------------------------------------------------------- 
| Id | Operation   | Name       | Rows | Bytes | Cost (%CPU)| Time  | 
--------------------------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT |        |  1 | 31 |  4 (0)| 00:00:01 | 
| 1 | SORT AGGREGATE |        |  1 | 31 |   |   | 
| 2 | NESTED LOOPS  |        | 406 | 12586 |  4 (0)| 00:00:01 | 
|* 3 | INDEX RANGE SCAN| INDEX_ON_TABLE_B   |  1 | 19 |  2 (0)| 00:00:01 | 
|* 4 | INDEX RANGE SCAN| PRIMARY_KEY_INDEX_OF_TABLE_A | 406 | 4872 |  2 (0)| 00:00:01 | 
--------------------------------------------------------------------------------------------------- 

Predicate Information (identified by operation id): 
--------------------------------------------------- 

    3 - access("b"."id"=1000) 
    4 - access("a"."key1"="b"."key1" and 
       "a"."key2"="b"."key2") 

lo tanto las filas (cardinalidad) estimado para el paso 4 es .

Ahora, un rastro TKPROF revela lo siguiente:

Rows  Row Source Operation 
------- --------------------------------------------------- 
     1 SORT AGGREGATE (cr=51 pr=9 pw=0 time=74674 us) 
    7366 NESTED LOOPS (cr=51 pr=9 pw=0 time=824941 us) 
     1 INDEX RANGE SCAN INDEX_ON_TABLE_B (cr=2 pr=0 pw=0 time=36 us)(object id 111111) 
    7366 INDEX RANGE SCAN PRIMARY_KEY_INDEX_OF_TABLE_A (cr=49 pr=9 pw=0 time=810173 us)(object id 222222) 

Así que la cardinalidad en la realidad era , no 406!

Mi pregunta es la siguiente: De dónde Oracle conseguir la cardinalidad estimado de 406 en este caso, y ¿Cómo puedo mejorar la precisión de, por lo que la estimación es más en la línea de lo que realmente sucede durante la ejecución de la consulta ?


Actualización: Aquí hay un fragmento de una traza 10053 me encontré en la consulta.

NL Join 
    Outer table: Card: 1.00 Cost: 2.00 Resp: 2.00 Degree: 1 Bytes: 19 
    Inner table: LARGE_PARTITIONED_TABLE Alias: a 
    ... 
    Access Path: index (IndexOnly) 
    Index: PRIMARY_KEY_INDEX_OF_TABLE_A 
    resc_io: 2.00 resc_cpu: 27093 
    ix_sel: 1.3263e-005 ix_sel_with_filters: 1.3263e-005 
    NL Join (ordered): Cost: 4.00 Resp: 4.00 Degree: 1 
     Cost_io: 4.00 Cost_cpu: 41536 
     Resp_io: 4.00 Resp_cpu: 41536 
    ****** trying bitmap/domain indexes ****** 
    Best NL cost: 4.00 
      resc: 4.00 resc_io: 4.00 resc_cpu: 41536 
      resp: 4.00 resp_io: 4.00 resp_cpu: 41536 
Using concatenated index cardinality for table SMALL_NONPARTITIONED_TABLE 
Revised join sel: 8.2891-e005 = 8.4475e-005 * (1/12064.00) * (1/8.4475e-005) 
Join Card: 405.95 = outer (1.00) * inner (4897354.00) * sel (8.2891-e005) 
Join Card - Rounded: 406 Computed: 405.95 

Así que de ahí viene el valor 406. Al igual que Adam respondió, unir cardinalidad es join selectivity * filter cardinality (a) * filter cardinality (b), como se puede ver en la penúltima línea de la cita de seguimiento anterior.

Lo que no entiendo es la línea Revised join sel. 1/12064 es la selectividad del índice utilizado para encontrar la fila de la tabla b (12064 filas en la tabla, y seleccionar en base a una identificación única). ¿Y qué?

  1. Cardinalidad parece ser calculado por multiplicando la cardinalidad filtro de la Tabla B (4.897.354) con selectividad de la tabla A (1/12064). ¿Por qué? ¿Qué tiene la selectividad en la tabla tiene que ver con la cantidad de filas se espera que se encuentre en tabla b, cuando a -> b unirse no se basa en a.id?

  2. Dónde se encuentra el número 8.4475e-005 vienen (no aparece en ningún otro lado en el rastro )? No es que afecte a la salida , pero aún me gustaría saberlo.

Entiendo que es probable que el optimizador haya elegido la ruta correcta aquí. Pero aún así el cardinalidad es calculado mal - y que puede tener un efecto importante en la ruta de ejecución que se elige a partir de ese punto en adelante (como en el caso que estoy teniendo IRL - este ejemplo es una simplificación de eso).

Respuesta

7

Generación de un archivo de traza 10053 ayudará a mostrar exactamente qué opciones de toma del optimizador con respecto a su estimación de cardinalidad y selectividad. Jonathan Lewis 'excellect Fundamentos de Oracle basados ​​en el costo es un recurso excelente para entender cómo funciona el optimizador, y la impresión que tengo abarca de 8i a 10.1.

A partir de ese trabajo:

Join Selectivity = ((num_rows(t1) - num_nulls(t1.c1))/num_rows(t1)) 
        * ((num_rows(t2) - num_nulls(t2.c2))/num_rows(t2)) 
       /greater (num_distinct(t1.c1), num_distinct(t2.c2)) 

Join Cardinality = Join Selectivity 
        * filtered_cardinality (t1) 
        * filtered_cardinality (t2) 

Sin embargo, porque tenemos una de varias columnas se unen, Ingreso Selectividad no está al nivel de la mesa, que es el producto (intersección) de las selectividades unirse en cada columna. Suponiendo que no es ningún nulos en juego:

Join Selectivity = Join Selectivity (key1) * Join Selectivity (key2) 

Join Selectivity (key1) = ((5,000,000 - 0)/5,000,000) 
          * ((10,000 - 0))/10,000) 
         /max (116, ?) -- distinct key1 values in B 

         = 1/max(116, distinct_key1_values_in_B) 

Join Selectivity (key2) = ((5,000,000 - 0)/5,000,000) 
          * ((10,000 - 0))/10,000) 
         /max (650, ?) -- distinct key2 values in B 

         = 1/max(650, distinct_key2_values in B) 

Join Cardinality = JS(key1) * JS(key2) 
        * Filter_cardinality(a) * Filter_cardinality(b) 

Sabemos que no hay filtros en A, por lo que la cardinalidad del filtro de tablas es el número de filas.Estamos seleccionando el valor de la clave de B, por lo que la cardinalidad de filtro de tabla es 1.

Así que el mejor de los casos para unirse Estimado Estimado cardinalidad está ahora

Join Cardinality = 1/116 * 1/650 * 5,000,000 * 1 

        =~ 67 

Puede ser que sea más fácil trabajar hacia atrás. Su cardinalidad estimada de 406, dado lo que sabemos, conduce a una selectividad de unión de 406/5,000,000, o aproximadamente 1/12315. Eso sucede realmente, muy cerca de 1/(116^2), que es un control de cordura dentro del optimizador para evitar que encuentre una cardinalidad demasiado agresiva en uniones de varias columnas.

Para el TL; DR multitud:

  1. Get Jonathan Lewis coste basados ​​Oracle Fundamentos.
  2. Obtenga un rastro 10053 de la consulta cuyo comportamiento no puede entender.
+0

Gracias Adam. Ciertamente echaré un vistazo al rastro 10053 de la consulta. Publicaré mis resultados mañana. – Tommi

+0

He actualizado la pregunta con la traza 10053, por favor vea arriba. – Tommi

+1

No puedo responder a la segunda pregunta: Oracle tiene muchos factores falsificados, y las reglas de cardinalidad del índice concatenados no están bien documentadas. Además, es un factor que se anula. La cardinalidad de unión AB se basa en la cardinalidad relativa de A (1 fila) multiplicada por la cardinalidad absoluta de B (4897354) multiplicada por la selectividad de unión - que es 1/cardinalidad absoluta de A. Míralo esto camino. Sus tablas asignan 12046 filas en A a 4897354 filas en B. Por lo tanto, para cada fila en A, hay, en promedio, 406 filas en B. –

2

La cardinalidad estimada se basaría en el producto de la selectividad de a.key1 y a.key2, que (al menos en 10g) se basarían en el número de valores distintos para esas dos columnas como se registra en el estadísticas de columnas

Para una tabla de filas de 5M, una estimación de cardinalidad de 406 no es significativamente diferente a 7366. La pregunta que debe hacerse es si la estimación "imprecisa" aquí causa un problema.

Puede comprobar cuál es el plan de Oracle elegiría si fuera capaz de generar una estimación muy exactos por conseguir un plan de explicación para esto:

select /*+CARDINALITY(a 7366)*/ count(a.id) 
from LARGE_PARTITIONED_TABLE a 
join SMALL_NONPARTITIONED_TABLE b on a.key1 = b.key1 and a.key2 = b.key2 
where b.id = 1000; 

Si esto le ocurre el mismo plan, entonces la estimación de que Oracle está calculando que ya es adecuado.

+0

Gracias Jeffrey. Por supuesto, tiene razón en que la diferencia de estimación de cardinalidad en este ejemplo no es significativa. Sin embargo, este es solo un caso simplificado que preparé para esta pregunta: tengo otros casos de consultas en las mismas tablas donde la diferencia es mucho mayor, y presumiblemente más significativo también. Todavía no puedo encontrar la fórmula que utiliza Oracle para llegar a la cardinalidad de 406. Num_distinct para las columnas a y b son 116 y 650, respectivamente. – Tommi

2

Le puede interesar leer este excelente artículo de Wolfgang Breitling que tiene mucha información sobre los cálculos de CBO: http://www.centrexcc.com/A%20Look%20under%20the%20Hood%20of%20CBO%20-%20the%2010053%20Event.pdf.

Como se explica allí, debido a que tiene histogramas, el cálculo del factor de filtro para estas columnas no utiliza el número de valores distintos (NDV) sino la densidad, que se deriva del histograma de alguna manera.

¿Cuáles son los valores de DENSIDAD en USER_TAB_COLUMNS para a.key1 y a.key2?

Generalmente, el problema en casos como este es que Oracle no recopila estadísticas sobre pares de columnas, y supone que su factor de filtro combinado será el producto de sus factores individuales. Esto producirá estimaciones bajas si existe alguna correlación entre los valores de las dos columnas.

Si esto está causando un problema serio de rendimiento, supongo que podría crear un índice basado en funciones sobre una función de esas columnas, y usar eso para hacer la búsqueda. Entonces Oracle reuniría estadísticas sobre ese índice y probablemente produciría mejores estimaciones.

+0

Gracias Dave, ese documento parece una lectura interesante. Necesito digerir esto un poco. ¡Publicaré los resultados mañana! – Tommi

+0

Ejecuté un rastreo 10053 en la consulta; consulte la pregunta actualizada. Los valores de densidad para a.key1 y a.key2 son 0,000000111 y 0,0022831. – Tommi

Cuestiones relacionadas