2009-04-28 13 views
34

Ho (ad esempio) un indice:Un indice a più colonne funziona anche per la selezione di una singola colonna?

CREATE INDEX someIndex ON orders (customer, date); 

Questo indice accelera solo le query in cui vengono utilizzati cliente e la data o lo fa accelerare le query per una singola colonna come anche questo?

SELECT * FROM orders WHERE customer > 33; 

Sto usando SQLite.


Se la risposta è sì, perché è possibile creare più di un indice per tabella?


Ancora un'altra domanda: quanto più veloce è un indice combinato confrontato con due indici separat quando si utilizzano entrambe le colonne in una query?

risposta

32

marc_s ha la risposta corretta alla prima domanda. La prima chiave in un indice multitasto può funzionare come un singolo indice di chiave, ma nessuna chiave successiva non lo farà.

Quanto a quanto più veloce l'indice composito dipende dai dati e dal modo in cui strutturate l'indice e la query, ma di solito è significativo. Gli indici essenzialmente permettono a Sqlite di fare una ricerca binaria sui campi.

Utilizzando l'esempio che ha dato se è stato eseguito l'interrogazione:

SELECT * from orders where customer > 33 && date > 99 

Sqlite dovrebbe prima ottenere tutti i risultati utilizzando una ricerca binaria su tutto il tavolo dove clienti> 33. Poi sarebbe fare una ricerca binaria su un solo quei risultati in cerca di data> 99.

Se si eseguiva la stessa query con due indici separati su cliente e data, Sqlite avrebbe dovuto eseguire una ricerca binaria sull'intera tabella due volte, prima per il cliente e nuovamente per la data.

Quindi, quanto di un aumento di velocità si vedrà dipende da come si struttura l'indice per quanto riguarda la query. Idealmente, il primo campo nel tuo indice e la tua query dovrebbero essere quelli che eliminano la maggior parte delle corrispondenze possibili in quanto ciò aumenterebbe la velocità riducendo notevolmente la quantità di lavoro che la seconda ricerca deve fare.

Per ulteriori informazioni vedere questo: http://www.sqlite.org/optoverview.html

+2

SQLite NON utilizzerà la seconda colonna di un indice se la prima colonna era un'espressione di disuguaglianza (ad es. Cliente> 33). (la maggior parte del motore di database sarebbe, difficile). – vmatyi

+1

Se si creano due indici separati, verrà utilizzato solo uno di essi, l'altra espressione verrà valutata sul set di risultati generato dal primo. (su un Oracle, è possibile eseguire la ricerca di due indici e intersecare i set di risultati, se l'ottimizzazione è basata sui costi e determinati criteri si incontrano, ma questo è un caso raro). – vmatyi

5

Sono abbastanza sicuro che funzionerà, sì, lo fa in MS SQL Server comunque.

Tuttavia, questo indice non è di aiuto se è necessario selezionare solo la data, ad es. un intervallo di date. In tal caso, potrebbe essere necessario creare un secondo indice solo sulla data per rendere tali query più efficienti.

Marc

+0

Grazie, è dove non ero sicuro. Creerò due indici separati in quel caso. –

3

I comunemente utilizzare gli indici per ordinare attraverso dati combinati desidero impaginare o richiesta "streamily".

Supponendo che un cliente possa effettuare più di un ordine ... e i clienti da 0 a 11 esistono e ci sono più ordini per cliente inseriti in ordine casuale. Voglio ordinare una query in base al numero cliente seguito dalla data. Dovresti ordinare il campo id anche l'ultimo per dividere i set in cui un cliente ha diverse date identiche (anche se ciò potrebbe non accadere mai).

sqlite> CREATE INDEX customer_asc_date_asc_index_asc ON orders 
      (customer ASC, date ASC, id ASC); 

Get Pagina 1 di una query ordinato (limitata a 10 articoli):

sqlite> SELECT id, customer, date FROM orders 
      ORDER BY customer ASC, date ASC, id ASC LIMIT 10; 

2653|1|1303828585 
2520|1|1303828713 
2583|1|1303829785 
1828|1|1303830446 
1756|1|1303830540 
1761|1|1303831506 
2442|1|1303831705 
2523|1|1303833761 
2160|1|1303835195 
2645|1|1303837524 

ottenere la pagina successiva:

sqlite> SELECT id, customer, date FROM orders WHERE 
      (customer = 1 AND date = 1303837524 and id > 2645) OR 
      (customer = 1 AND date > 1303837524) OR 
      (customer > 1) 
      ORDER BY customer ASC, date ASC, id ASC LIMIT 10; 

2515|1|1303837914 
2370|1|1303839573 
1898|1|1303840317 
1546|1|1303842312 
1889|1|1303843243 
2439|1|1303843699 
2167|1|1303849376 
1544|1|1303850494 
2247|1|1303850869 
2108|1|1303853285 

E così via ...

Avere gli indici in posizione riduce la scansione dell'indice lato server quando altrimenti si utilizzerà una query OFFSET associata a un LIMIT. Il tempo di interrogazione si allunga e le unità cercano più difficile quanto più alto è l'offset. L'utilizzo di questo metodo lo elimina.

L'utilizzo di questo metodo è consigliato se si pianifica di unire i dati in un secondo momento, ma è sufficiente una serie limitata di dati per richiesta. Unisciti a un SUBSELECT come descritto sopra per ridurre il sovraccarico della memoria per i tavoli di grandi dimensioni.

+0

Questo aiuta anche a eliminare il tempo di comando lato server non necessario ... se dovessi usare ** datetime (data, 'unixepoch', 'localtime') ** invece di ** date ** come colonna di ritorno .. sarebbe sicuramente essere limitato Credo che sarebbe comunque - dipende dal motore. – whardier

Problemi correlati