2009-12-03 12 views
25

ho incontrato questa domanda in un'intervista e non aveva idea di come rispondere:Forza utilizzo indice in Oracle

c'è un tavolo che ha un indice su una colonna, e la tua ricerca:

select * from table_name where column_having_index="some value"; 

La query impiega troppo tempo e scopri che l'indice non viene utilizzato. Se pensi che il rendimento della query sarà migliore usando l'indice, come potresti forzare la query a utilizzare l'indice?

risposta

37

È possibile utilizzare l'ottimizzatore accenna

select /*+ INDEX(table_name index_name) */ from table ecc ...

ulteriori informazioni sull'uso di hint di ottimizzazione: http://download.oracle.com/docs/cd/B19306_01/server.102/b14211/hintsref.htm

+1

Inoltre, nelle versioni più recenti di Oracle (10g + penso) è possibile specificare il nome della colonna anziché il nome dell'indice, ad es. '/ * + INDICE (nome_tabella column_having_index) * /' –

+1

/* + INDICE (nome_tabella (column_having_index)) */... opr vedere la mia risposta per sintassi più complessa –

+1

La sintassi corretta è (devi usare l'alias di tabella!): seleziona/* + INDICE (xxxTABLExxx index_name) */da table_name xxxTABLExxx – xnagyg

-4

È possibile utilizzare:

WITH index = ... 

more info

+0

ohh .. pensavi significasse MS-Sql ... ma ti viene l'idea :) – Leon

2

C'è un indice appropriato su column_having_index e il suo uso aumenta le prestazioni, ma Oracle non lo usa ...
Si dovrebbe raccogliere statistiche sul proprio tavolo per consentire all'ottimizzatore di vedere che l'accesso all'indice può essere d'aiuto. Utilizzare il suggerimento diretto non è una buona pratica.

+1

I suggerimenti per l'indicizzazione dovrebbero essere usati con parsimonia ma ci sono molti legittimi situazioni per il loro utilizzo. Un esempio è dove le statistiche non sono disponibili per dimostrare che i valori delle colonne sono fortemente correlati e il CBO deduce una cardinalità errata per i predicati su più colonne. –

+1

David, per quanto riguarda la domanda, l'esempio è così semplice che non vedo alcun motivo per CBO di non utilizzare l'indice di salvataggio per statistiche errate. Ma in generale, hai ragione, ovviamente. –

13

Ci potrebbero essere molte ragioni per l'indice non utilizzato. Anche dopo averlo specify hints, ci sono possibilità che Oracle Optimizer pensi diversamente e decidere di non utilizzare l'indice. È necessario passare attraverso la parte PLAN EXPLAIN e vedere qual è il costo dell'istruzione con INDICE e senza INDICE.

Assumendo il Oracle uses CBO. Molto spesso, se l'ottimizzatore ritiene che il costo sia elevato con INDICE, anche se lo si specifica nei suggerimenti, l'ottimizzatore ignorerà e continuerà per la scansione completa della tabella. La tua prima azione dovrebbe essere controllare DBA_INDEXES per sapere quando le statistiche sono LAST_ANALYZED. Se non analizzato, è possibile set table, index for analyze.

begin 
    DBMS_STATS.GATHER_INDEX_STATS (OWNNAME=>user 
           , INDNAME=>IndexName); 
end; 

Per tavolo.

begin 
    DBMS_STATS.GATHER_TABLE_STATS (OWNNAME=>user 
           , TABNAME=>TableName); 
end; 

In casi estremi, si può provare setting up the statistics da soli.

+0

Il CBO "onorerà" sempre tutti * i suggerimenti * correttamente specificati - non ha la libertà di "scegliere" arbitrariamente di non onorare un suggerimento. –

+4

Molto recentemente abbiamo aggiornato ORA 9208 da ORA 9205, in seguito, abbiamo riscontrato questo, c'era una query complessa, INDICE non è stato utilizzato. L'ho forzato con il SUGGERIMENTO. Anche se EXPLAIN_PLAN ha mostrato di utilizzare l'INDICE, quando è stato eseguito ha preso il percorso diverso. Questo è quando DBA ci ha suggerito di riscrivere l'SQL. E l'abbiamo fatto, ha funzionato. – Guru

9

Se pensi che le prestazioni della query saranno migliori utilizzando l'indice, come potresti forzare la query a utilizzare l'indice?

In primo luogo, si dovrebbe ovviamente verificare che l'indice abbia dato un risultato migliore per la restituzione del set di dati completo, giusto?

Il suggerimento indice è la chiave qui, ma il modo più aggiornato di specificarlo è con il metodo di denominazione delle colonne piuttosto che con il metodo di denominazione dell'indice. Nel tuo caso useresti:

select /*+ index(table_name (column_having_index)) */ * 
from table_name 
where column_having_index="some value"; 

In casi più complessi potresti ...

select /*+ index(t (t.column_having_index)) */ * 
from my_owner.table_name t, 
     ... 
where t.column_having_index="some value"; 

Per quanto riguarda gli indici compositi, non sono sicuro che si bisogno di specificare tutte le colonne, ma sembra una buona idea. Vedere i documenti qui http://docs.oracle.com/cd/E11882_01/server.112/e26088/sql_elements006.htm#autoId18 su più index_specs e uso di index_combine per più indici, e qui http://docs.oracle.com/cd/E11882_01/server.112/e26088/sql_elements006.htm#BABGFHCH per la specifica di più colonne in index_spec.

+0

E se l'indice coinvolge più colonne? Devo specificare tutti loro? – shindigo

+0

Migliorata la risposta per più colonne, @shindigo –

Problemi correlati