2010-07-01 10 views
5

Ho una 10.2.0.3 database Oracle, e una query come questa:Oracle spiegare il piano previsionale delle cardinalità non corretta per una gamma di indice di scansione

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 

Tabella LARGE_PARTITIONED_TABLE (a) ha circa 5 milioni di righe, ed è partizionato da una colonna non presente nella query. La tabella SMALL_NONPARTITIONED_TABLE (b) non è partizionata e contiene circa 10000 righe.

Le statistiche sono aggiornate e sono presenti istogrammi bilanciati in altezza nelle colonne key1 e key2 della tabella a.

La tabella a ha una chiave primaria e un indice univoco globale non partizionato sulle colonne key1, key2, key3, key4 e key5.

Spiega piano per l'interrogazione visualizza i seguenti risultati:

--------------------------------------------------------------------------------------------------- 
| 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") 

quindi il file (cardinalità) stimato per il passaggio 4 è .

Ora, un TKPROF traccia rivela quanto segue:

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) 

Così la cardinalità in realtà era , non 406!

mia domanda è questa: Da dove viene Oracle ottiene la cardinalità stimata di 406 in questo caso, e Come posso migliorare la sua accuratezza, in modo che la stima è più in linea di ciò che accade realmente durante l'esecuzione di query ?


Aggiornamento: Ecco un frammento di una traccia 10053 mi sono imbattuto sulla query.

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 

Ecco da dove viene il valore 406. Come ha risposto Adam, unire la cardinalità è join selectivity * filter cardinality (a) * filter cardinality (b), come si può vedere nella penultima frase della penultima traccia.

Quello che non capisco è la linea Revised join sel. 1/12064 è la selettività dell'indice utilizzato per trovare la riga dalla tabella b (12064 righe sulla tabella e selezionare in base all'ID univoco). Ma allora cosa?

  1. cardinalità sembra essere calcolato moltiplicando cardinalità filtro di tabella b (4.897.354) con selettività tavolo un (1/12064). Perché? Che cosa è la tabella di selettività nella tabella a quanto si deve trovare righe da tabella b, quando un join -> b non è basato su a.id?

  2. Da dove viene il numero 8.4475e-005 provengono da (non appare da nessun'altra parte nell'intera traccia )? Non che ciò influisca sull'output , ma mi piacerebbe comunque saperlo.

Capisco che l'ottimizzatore abbia probabilmente scelto il percorso corretto qui. Ma ancora la cardinalità viene calcolato male - e che può avere un effetto importante sul percorso di esecuzione che viene scelto da quel punto in poi (come nel caso sto avendo IRL - questo esempio è una semplificazione di quello).

risposta

7

Generazione di un file di traccia 10053 aiuterà spettacolo esattamente quali scelte per la preparazione del ottimizzatore quanto riguarda la sua stima della cardinalità e la selettività. L'excelletto di Jonathan Lewis Fondamentali Oracle basati sul costo è un'ottima risorsa per capire come funziona l'ottimizzatore e la stampa che ho occupa da 8i a 10.1.

Da quel lavoro:

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) 

Tuttavia, perché abbiamo un multi-colonna di join, Registrazione selettività non è a livello di tabella, è il prodotto (intersezione) della selettività aderire su ogni colonna. Supponendo c'è nulli in gioco:

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) 

Sappiamo che ci sono filtri su A, in modo che di filtro tabelle cardinalità è il numero di righe.Stiamo selezionando il valore chiave da B, in modo cardinalità filtro di tabella è 1.

Così il caso migliore per stimate stimato unirsi cardinalità è ora

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

        =~ 67 

Potrebbe essere più facile lavorare a ritroso. La tua cardinalità stimata di 406, in base a ciò che sappiamo, porta ad una selezione di adesioni di 406/5.000.000 o circa 1/12315. Questo è veramente, molto vicino a 1/(116^2), che è un controllo di integrità all'interno dell'ottimizzatore per evitare di trovare una cardinalità troppo aggressiva sui join a più colonne.

Per la TL; DR folla:

  1. Get Jonathan Lewis' costo in base Oracle Fundamentals.
  2. Ottieni una traccia 10053 della query il cui comportamento non può essere compreso.
+0

Grazie Adam. Darò sicuramente un'occhiata alla traccia 10053 della query. Pubblicherò i miei risultati domani. – Tommi

+0

Ora ho aggiornato la domanda con la traccia 10053, vedere sopra. – Tommi

+1

Non riesco a rispondere alla seconda domanda: Oracle ha molti fattori fondenti e le regole di cardinalità dell'indice concatenate non sono ben documentate. Inoltre, è un fattore che si annulla. Il AB join cardinalità si basa sulla relativa cardinalità di A (1 fila) moltiplicato per la cardinalità assoluta di B (4.897.354) moltiplicato per la selettività join - che è 1/cardinalità assoluto di A. guardare in questo modo. Le tue tabelle associano 12046 righe in A a 4897354 righe in B. Pertanto, per ogni riga in A, ci sono, in media, 406 righe in B. –

2

La stima di cardinalità si baserebbe sul prodotto della selettività di a.key1 e a.key2, che (almeno in 10 g) sarebbero basati sul numero di valori distinti per le due colonne come registrato nel statistiche di colonna.

Per una tabella di 5 milioni di righe, una stima di cardinalità di 406 non è significativamente diversa da 7366. La domanda che devi porsi è, è la stima "imprecisa" che causa un problema?

È possibile controllare quale piano Oracle avrebbe scelto se fosse in grado di generare una stima perfettamente accurato da ottenere un spiegare piano per questo:

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; 

Se questo si presenta con lo stesso piano, allora la stima che Oracle sta calcolando è già adeguato.

+0

Grazie Jeffrey. Ovviamente hai ragione nel ritenere che la differenza di stima della cardinalità in questo esempio non sia significativa. Tuttavia, questo è solo un caso semplificato che ho preparato per questa domanda - ho altri casi di domande contro le stesse tabelle in cui la differenza è molto più grande - e presumibilmente più significativa. io sono ancora in grado di venire con la formula Oracle utilizza per arrivare a cardinalità 406. Num_distinct per colonne A e B sono rispettivamente 116 e 650,. – Tommi

2

Potreste essere interessati a leggere questo ottimo articolo di Wolfgang Breitling che ha un sacco di informazioni su calcoli CBO: http://www.centrexcc.com/A%20Look%20under%20the%20Hood%20of%20CBO%20-%20the%2010053%20Event.pdf.

Come spiegato qui, poiché si dispone di istogrammi, il calcolo del fattore di filtro per queste colonne non utilizza il numero di valori distinti (NDV) ma la densità, che è derivata dall'istogramma in qualche modo.

Quali sono i valori DENSITY in USER_TAB_COLUMNS per a.key1 e a.key2?

In genere, il problema in casi come questo è che Oracle non raccoglie statistiche su coppie di colonne e presuppone che il loro fattore di filtro combinato sarà il prodotto dei loro singoli fattori. Ciò produrrà stime basse se esiste una correlazione tra i valori delle due colonne.

Se questo sta causando un grave problema di prestazioni, suppongo che si possa creare un indice basato su funzioni su una funzione di queste colonne, e l'uso che per fare la ricerca. Quindi Oracle raccoglierà statistiche su quell'indice e probabilmente produrrà stime migliori.

+0

Grazie a Dave, quella carta sembra davvero una lettura interessante. Ho bisogno di digerirlo un po '- posterò i risultati domani! – Tommi

+0

Ho eseguito una traccia 10053 nella query: vedere la domanda aggiornata. I valori di densità per a.key1 e a.key2 sono 0,000000111 e 0,0022831. – Tommi

Problemi correlati