Domanda

Ho questo tavolo:

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

E questo indice:

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

Quando eseguo questa domanda

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

EXPLAIN PLAN mostra che fa una scansione a tavola intera. Quindi ho lasciato cadere l'indice e l'ho creato di nuovo. EXPLAIN PLAN dice ancora la scansione a tavola intera. Come può essere?

Alcuni background: si tratta di dati storici, quindi ciò che accade è che cerco una riga con lo stato CLEARED e inserire una nuova riga con stato NEW (Inoltre copio alcuni valori dalla vecchia riga). La vecchia riga viene quindi aggiornata USED. Quindi il tavolo cresce sempre. Quello che ho notato è che la cardinalità dell'indice è 0 (nonostante abbia migliaia di valori diversi). Dopo la ricreazione, la cardinalità è cresciuta ma al CBO non è piaciuto meglio l'indice.

La mattina dopo, a Oracle improvvisamente piaceva l'indice (probabilmente dormiva su di esso) e iniziò a usarlo ma non a lungo. Dopo un po ', l'elaborazione è scesa da 50 righe/s a 3 righe/se ho visto di nuovo "Scansione completa". Cosa sta succedendo?

Nel mio caso, devo elaborare circa un milione di file. Impegno i cambiamenti nei lotti di ca. 50. Esiste un comando che dovrei eseguire dopo un impegno per aggiornare/rearg l'indice o qualcosa del genere?

Sono su Oracle 10G.

Modifica] Ho 969'491 chiavi distinte in questa tabella, 3 tipi e 3 stati.

È stato utile?

Soluzione

Cosa succede se specifichi un suggerimento dell'indice? Prova questo:

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

Sembra che quello che è successo durante la notte sia che il tavolo è stato analizzato. Quindi, mentre eseguiva l'elaborazione contro la tabella, abbastanza dell'indice è stato aggiornato per causare nuovamente stantii stanti di Oracle's Table e l'ottimizzatore ha smesso di usare l'indice.

Aggiungi il suggerimento e vedi se il piano spiega ti dà un piano diverso e la query funziona meglio.

Oh, e la risposta di Tony sull'analisi del tavolo è una buona pratica generale, anche se con 10G il database è abbastanza bravo a fare l'auto-manutenzione in questo senso. Se il tuo processo sta facendo molti aggiornamenti, l'indice può diventare stantio rapidamente. Se eseguire Analizza quando il processo inizia ad andare nel fossato migliora la situazione per un po ', sapresti che questo è il problema.

Per aggiornare le statistiche per la tabella, utilizzare il DMBS_STATS.GATHER_TABLE_STATS pacchetto.

Per esempio:

Exec dbms_stats.gather_table_stats ("il proprietario", "demo");

Altri suggerimenti

La tabella è stata analizzata di recente? Se Oracle pensa che sia molto piccolo, potrebbe non considerare nemmeno l'uso dell'indice.

Prova questo:

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

Num_Rows ti dice quante righe Oracle pensa che la tabella contenga.

"La mattina dopo, a Oracle è piaciuto improvvisamente l'indice (probabilmente ha dormito su di esso)" Probabilmente un DBMS_STATS è in esecuzione durante la notte.

Generalmente vedrei uno dei tre motivi per una tabella completa su un indice. Il primo è che l'ottimizzatore pensa che il tavolo sia vuoto, o almeno molto piccolo. Sospetto che questo sia stato il problema iniziale. In tal caso sarebbe più veloce a scansionare a pieno titolo una tabella costituita da solo una manciata di blocchi piuttosto che utilizzare un indice.

Il secondo è quando la query è tale che un indice non può essere praticamente utilizzato.

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

Stai effettivamente usando i letterali codificati nella query. In caso contrario, i tuoi dati variabili potrebbero essere errati (EG Key Essere Carattere). Ciò richiederebbe che la chiave numerica venga convertita in carattere per il confronto, il che renderebbe l'indice quasi inutile.

Il terzo motivo è dove pensa che la query elaborerà gran parte delle righe nella tabella. Il tipo e lo stato sembrano una cardinalità piuttosto bassa. Forse hai un gran numero di un valore "chiave" specifico?

Un commento sull'elaborazione che descrivi: sembra che tu stia facendo elaborazione a righe con commessi intermittenti e ti esorto a ripensare questo se puoi. Il meccanismo di aggiornamento/inserto potrebbe essere convertito in un'istruzione di unione e l'intero set di dati può quindi essere elaborato in un'unica istruzione con un commit alla fine. Ciò sarebbe quasi certamente più veloce e utilizzerebbe meno risorse del tuo metodo attuale.

Il valore della chiave di colonna è sempre 1? In tal caso, non sono sicuro che consultare l'indice ottimizzerebbe la query, poiché ogni riga dovrebbe essere esaminata comunque. In tal caso, dichiarare l'indice senza la colonna chiave. Potresti anche provare:

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

Quale (se la mia ipotesi è giusta) dovrebbe comunque guardare ogni riga, ma che potrebbe andare all'indice poiché tutte le colonne nel set di risultati sono ora coperte.

Sto solo indovinando in base alla tua affermazione che l'indice mostra cardinalità 0.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top