Devi fare una ricerca per ogni dove condizione e per ogni join... a condizione. I due funzionano allo stesso modo.
Supponiamo di scrivere
select name
from customer
where customerid=37;
In qualche modo il DBMS deve trovare il record o i record con customerid=37. Se non c'è un indice, l'unico modo per farlo è leggere ogni record nella tabella confrontando il customerid con 37. Anche quando ne trova uno, non ha modo di sapere che ce n'è solo uno, quindi deve continuare a cercare altri.
Se crei un indice su customerid, il DBMS ha modi per cercare l'indice molto rapidamente. Non è una ricerca sequenziale, ma, a seconda del database, una ricerca binaria o qualche altro metodo efficiente. Esattamente come non importa, accetta che è molto più veloce del sequenziale. L'indice quindi lo porta direttamente al record o ai record appropriati. Inoltre, se si specifica che l'indice è "unico", il database sa che può essercene solo uno per non perdere tempo a cercare un secondo. (E il DBMS ti impedirà di aggiungere un secondo.)
Ora considera questa query:
select name
from customer
where city='Albany' and state='NY';
Ora abbiamo due condizioni. Se hai un indice solo su uno di questi campi, il DBMS utilizzerà quell'indice per trovare un sottoinsieme di record, quindi cercherà in sequenza quelli. Ad esempio, se hai un indice su stato, il DBMS troverà rapidamente il primo record per NY, quindi cercherà in sequenza cercando city='Albany' e smetterà di cercare quando raggiunge l'ultimo record per NY.
Se hai un indice che include entrambi i campi, ad es. "crea indice sul cliente (stato, città)", il DBMS può immediatamente ingrandire i record corretti.
Se hai due indici separati, uno su ogni campo, il DBMS avrà varie regole che applica per decidere quale indice usare. Ancora una volta, esattamente come questo viene fatto dipende dal particolare DBMS che stai utilizzando, ma fondamentalmente cerca di mantenere statistiche sul numero totale di record, sul numero di valori diversi e sulla distribuzione dei valori. Quindi cercherà in sequenza quei record per quelli che soddisfano l'altra condizione. In questo caso, il DBMS osserverebbe probabilmente che ci sono molte più città che stati, quindi utilizzando l'indice delle città è possibile ingrandire rapidamente i record "Albany". Quindi li cercherà in sequenza, controllando lo stato di ciascuno rispetto a "NY". Se disponi di record per Albany, California, questi verranno ignorati.
Ogni join richiede una sorta di ricerca.
Diciamo che scriviamo
select customer.name
from transaction
join customer on transaction.customerid=customer.customerid
where transaction.transactiondate='2010-07-04' and customer.type='Q';
Ora il DBMS deve decidere quale tabella leggere per prima, selezionare i record appropriati da lì, quindi trovare i record corrispondenti nell'altra tabella.
Se si dispone di un indice su transaction.transactiondate e customer.customerid, il piano migliore sarebbe probabilmente trovare tutte le transazioni con questa data, quindi per ognuna di queste trovare il cliente con l'id cliente corrispondente, quindi verificare che il cliente abbia il tipo giusto.
Se non si dispone di un indice su customer.customerid, il DBMS potrebbe trovare rapidamente la transazione, ma per ogni transazione dovrebbe cercare in sequenza la tabella dei clienti alla ricerca di un customerid corrispondente. (Questo sarebbe probabilmente molto lento.)
Supponiamo invece che gli unici indici che hai siano su transaction.customerid e customer.type. Quindi il DBMS utilizzerebbe probabilmente un piano completamente diverso. Probabilmente eseguirà la scansione della tabella dei clienti per tutti i clienti con il tipo corretto, quindi per ciascuno di questi troverà tutte le transazioni per questo cliente e le cercherà in sequenza per la data giusta.
La chiave più importante per l'ottimizzazione è capire quali indici possono davvero aiutare e creare quegli indici. Gli indici extra non utilizzati sono un onere per il database perché la loro manutenzione richiede del lavoro e se non vengono mai utilizzati è uno sforzo inutile.
Puoi dire quali indici utilizzerà il DBMS per una determinata query con il comando EXPLAIN. Lo uso sempre per determinare se le mie query vengono ottimizzate correttamente o se dovrei creare indici aggiuntivi. (Leggi la documentazione su questo comando per una spiegazione del suo output.)
Avvertenza:ricorda che ho detto che il DBMS mantiene statistiche sul numero di record e sul numero di valori diversi e così via in ogni tabella. EXPLAIN potrebbe darti un piano completamente diverso oggi rispetto a ieri se i dati sono cambiati. Ad esempio, se si dispone di una query che unisce due tabelle e una di queste tabelle è molto piccola mentre l'altra è grande, sarà orientata a leggere prima la tabella piccola e quindi a trovare i record corrispondenti nella tabella grande. L'aggiunta di record a una tabella può cambiare che è più grande, e quindi portare il DBMS a cambiare il suo piano. Pertanto, dovresti tentare di eseguire EXPLAINS su un database con dati realistici. L'esecuzione su un database di prova con 5 record in ogni tabella ha un valore molto inferiore rispetto all'esecuzione su un database attivo.
Beh, c'è molto altro da dire, ma non voglio scrivere un libro qui.