Domanda

Supponiamo di avere una tabella di database con due campi, "pippo". e "barra". Nessuno dei due è unico, ma ciascuno di essi è indicizzato. Tuttavia, anziché essere indicizzati insieme, ognuno di essi ha un indice separato.

Ora supponiamo che io esegua una query come SELECT * FROM someable WHERE foo = 'hello' AND bar = 'world'; La mia tabella un numero enorme di righe per le quali foo è 'hello' e un piccolo numero di righe per le quali la barra è "mondo".

Quindi la cosa più efficiente che il server di database deve fare sotto il cofano è usare l'indice della barra per trovare tutti i campi in cui la barra è 'world', quindi restituire solo quelle righe per le quali foo è 'hello'. Questo è O (n) dove n è il numero di righe in cui la barra è 'world'.

Tuttavia, immagino sia possibile che il processo avvenga al contrario, dove è stato utilizzato l'indice fo e i risultati sono stati cercati. Questo sarebbe O (m) dove m è il numero di righe in cui foo è 'ciao'.

Quindi Oracle è abbastanza intelligente da cercare in modo efficiente qui? E gli altri database? O c'è un modo in cui posso dirlo nella mia query per cercare nell'ordine corretto? Forse inserendo bar = 'world' nella clausola WHERE ?

È stato utile?

Soluzione

Oracle utilizzerà quasi sicuramente l'indice più selettivo per guidare la query e puoi verificarlo con il piano esplicativo.

Inoltre, Oracle può combinare l'uso di entrambi gli indici in un paio di modi: può convertire gli indici btree in bitmap ed eseguire un'operazione bitmap e su di essi, oppure può eseguire un hash join sul rowid restituito dai due indici.

Una considerazione importante qui potrebbe essere qualsiasi correlazione tra i valori da interrogare. Se foo = 'hello' rappresenta l'80% dei valori nella tabella e bar = 'world' rappresenta il 10%, Oracle stimerà che la query restituirà 0,8 * 0,1 = 8% delle righe della tabella. Tuttavia, ciò potrebbe non essere corretto: la query potrebbe effettivamente restituire il 10% dei rwos o addirittura lo 0% delle righe a seconda della correlazione dei valori. Ora, a seconda della distribuzione di quelle righe nella tabella, potrebbe non essere efficiente usare un indice per trovarle. Potrebbe essere necessario accedere (diciamo) al 70% o ai blocchi di tabella per recuperare le righe richieste (google per "fattore di clustering"), nel qual caso Oracle eseguirà una scansione completa della tabella se la stima è corretta.

In 11g puoi raccogliere statistiche a più colonne per aiutare in questa situazione, credo. In 9i e 10g è possibile utilizzare il campionamento dinamico per ottenere un'ottima stima del numero di righe da recuperare.

Per ottenere il piano di esecuzione, procedere come segue:

explain plan for
SELECT *
FROM   sometable
WHERE  foo='hello' AND bar='world'
/
select * from table(dbms_xplan.display)
/

Contrasta quello con:

explain plan for
SELECT /*+ dynamic_sampling(4) */
       *
FROM   sometable
WHERE  foo='hello' AND bar='world'
/
select * from table(dbms_xplan.display)
/

Altri suggerimenti

Sì, puoi dare " suggerimenti " con la query a Oracle. Questi suggerimenti sono mascherati da commenti (" / * HINT * / ") al database e sono principalmente specifici del fornitore. Pertanto, un suggerimento per un database non funzionerà su un altro database.

Vorrei usare i suggerimenti sull'indice qui, il primo suggerimento per la piccola tabella. Vedi qui .

D'altra parte, se cerchi spesso su questi due campi, perché non creare un indice su questi due? Non ho la sintassi giusta, ma sarebbe qualcosa di simile

CREATE INDEX IX_BAR_AND_FOO on sometable(bar,foo);

In questo modo il recupero dei dati dovrebbe essere piuttosto veloce. E nel caso in cui la concatenazione sia unica quando si crea semplicemente un indice unico che dovrebbe essere velocissimo.

Eli,

In un commento hai scritto:

  

Sfortunatamente, ho una tabella con molte colonne ognuna con il proprio indice. Gli utenti possono eseguire query su qualsiasi combinazione di campi, quindi non posso creare in modo efficiente indici su ciascuna combinazione di campi. Ma se avessi solo due campi che necessitavano di indici, sarei completamente d'accordo con il tuo suggerimento di usare due indici. & # 8211; Eli Courtwright (29 settembre alle 15:51)

Questa è in realtà un'informazione piuttosto cruciale. A volte i programmatori superano se stessi quando fanno domande. Tentano di distillare la domanda fino ai punti fondamentali ma molto spesso semplificano e non ottengono la risposta migliore.

Questo scenario è precisamente il motivo per cui sono stati inventati gli indici bitmap - per gestire i tempi in cui i gruppi sconosciuti di colonne sarebbero stati utilizzati in una clausola where.

Nel caso in cui qualcuno dica che gli IMC sono solo per colonne con cardinalità bassa e potrebbero non essere applicabili al tuo caso. Basso probabilmente non è piccolo come pensi. L'unico vero problema è la concorrenza di DML nella tabella. Per funzionare, deve essere a thread singolo o raro.

  

Quindi Oracle è abbastanza intelligente da cercare   efficiente qui?

La risposta semplice è "probabilmente". Ci sono molte persone molto brillanti in ciascuno dei fornitori di database che lavorano per ottimizzare Query Optimizer, quindi probabilmente sta facendo cose a cui non hai nemmeno pensato. E se aggiorni le statistiche, probabilmente farà ancora di più.

Prima di tutto, assumerò che tu stia parlando di indici b * -tree normali, normali e standard. La risposta per gli indici bitmap è radicalmente diversa. E ci sono molte opzioni per vari tipi di indici in Oracle che possono o meno cambiare la risposta.

Come minimo, se l'ottimizzatore è in grado di determinare la selettività di una particolare condizione, utilizzerà l'indice più selettivo (ovvero l'indice sulla barra). Ma se hai dati distorti (ci sono N valori nella barra della colonna ma la selettività di qualsiasi valore particolare è sostanzialmente più o meno di 1 / N dei dati), per poter dire che dovresti avere un istogramma sulla colonna l'ottimizzatore quali valori sono più o meno probabili. E se stai usando variabili bind (come dovrebbero fare tutti gli sviluppatori OLTP validi), a seconda della versione di Oracle, potresti avere problemi con la visualizzazione delle variabili bind.

Potenzialmente, Oracle potrebbe persino eseguire una conversione al volo dei due indici b * -ree in bitmap e combinare le bitmap per utilizzare entrambi gli indici per trovare le righe necessarie per recuperare. Ma questo è un piano di query piuttosto insolito, in particolare se ci sono solo due colonne in cui una colonna è altamente selettiva.

Sono sicuro che anche Oracle può visualizzare un piano di query in modo da poter vedere esattamente quale indice viene utilizzato per primo.

Puoi fornire suggerimenti su quale indice utilizzare. Non ho familiarità con Oracle, ma in Mysql puoi usare USE | IGNORE | FORCE_INDEX (vedi qui per maggiori dettagli). Per prestazioni ottimali, tuttavia, è necessario utilizzare un indice combinato.

L'approccio migliore sarebbe aggiungere foo all'indice di bar, o aggiungere bar all'indice di foo (o entrambi). Se l'indice di foo contiene anche un indice su barra, quel livello di indicizzazione aggiuntivo non influirà sull'utilità dell'indice di foo in qualsiasi uso corrente di tale indice, né influenzerà sensibilmente le prestazioni di mantenimento di tale indice, ma fornirà al database ulteriori informazioni su cui lavorare per ottimizzare le query come nell'esempio.

È meglio di così.

Le ricerche dell'indice sono sempre più veloci delle scansioni di tabelle complete. Quindi dietro le quinte Oracle (e il server SQL per quella materia) localizzeranno innanzitutto l'intervallo di righe su entrambi gli indici. Vedrà quindi quale intervallo è più breve (visto che si tratta di un join interno) e ripeterà l'intervallo più corto per trovare le corrispondenze con il più grande dei due.

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