Ho bisogno di indici separati per ogni tipo di query o funzionerà un indice multi-colonna?


22

In qualche modo conosco già la risposta a questa domanda, ma ho sempre la sensazione che ci sia qualcosa di più che devo imparare sull'argomento.

La mia comprensione di base è che in generale, un singolo indice che include solo tutti i campi su cui potresti eseguire query / ordinamento in un dato momento non è probabilmente utile, ma ho visto questo tipo di cose. Come in, qualcuno ha pensato: "Beh, se mettiamo tutte queste cose in un indice, il database può usarlo per trovare ciò di cui ha bisogno", senza aver mai visto un piano di esecuzione per alcune delle query effettive in esecuzione.

Immagina un tavolo come questo:

id int pk/uid
name varchar(50)
customerId int (foreign key)
dateCreated datetime

Potrei vedere un unico indice compresi i name, customerIde dateCreatedcampi.

Ma la mia comprensione è che un tale indice non verrebbe utilizzato in una query come, ad esempio:

SELECT [id], [name], [customerId], [dateCreated]
   FROM Representatives WHERE customerId=1 
   ORDER BY dateCreated

Per una domanda del genere, mi sembra che un'idea migliore sarebbe un indice che includa i campi customerIde dateCreated, con il customerIdcampo "primo". Ciò creerebbe un indice che dovrebbe organizzare i dati in modo tale che questa query possa trovare rapidamente ciò di cui ha bisogno, nell'ordine in cui è necessaria.

Un'altra cosa che vedo, forse con la stessa frequenza della prima, sono i singoli indici su ciascun campo; così, uno ciascuno su name, customerIde dateCreatedcampi.

A differenza del primo esempio, questo tipo di arrangiamento mi sembra a volte almeno parzialmente utile; il piano di esecuzione della query potrebbe mostrare che almeno sta usando l'indice su customerIdper selezionare i record, ma non sta usando l'indice con il dateCreatedcampo per ordinarli.


So che questa è una domanda ampia, perché la risposta specifica a una particolare query su un particolare set di tabelle è in genere quella di vedere cosa dice il piano di esecuzione e altrimenti prendere le specifiche delle tabelle e delle query in account. Inoltre, so che dipende dalla frequenza con cui una query potrebbe essere eseguita rispetto al sovraccarico di mantenere un determinato indice per esso.

Ma suppongo che ciò che sto chiedendo sia come un "punto di partenza" generale per gli indici, ha senso l'idea di avere indici specifici per query specifiche, frequentemente estratte e i campi nelle clausole WHERE o ORDER BY?

Risposte:


27

Hai ragione nel dire che la tua query di esempio non userebbe quell'indice.

Il pianificatore di query prenderà in considerazione l'utilizzo di un indice se:

  • tutti i campi in esso contenuti sono indicati nella query
  • si fa riferimento ad alcuni campi a partire dall'inizio

Non sarà in grado di utilizzare gli indici che iniziano con un campo non utilizzato dalla query.

Quindi, per il tuo esempio:

SELECT [id], [name], [customerId], [dateCreated]
   FROM Representatives WHERE customerId=1 
   ORDER BY dateCreated

considererebbe indici come:

[customerId]
[customerId], [dateCreated]
[customerId], [dateCreated], [name]

ma no:

[name], [customerId], [dateCreated]

Se trovasse entrambi [customerId]e la [customerId], [dateCreated], [name]sua decisione di preferire l'una all'altra dipenderebbe dalle statistiche dell'indice che dipendono dalle stime del bilancio dei dati nei campi. Se [customerId], [dateCreated]fosse definito, dovrebbe preferire questo rispetto agli altri due, a meno che non si fornisca un suggerimento specifico sull'indice.

Non è raro vedere un indice definito per ogni campo nella mia esperienza, anche se questo è raramente ottimale poiché la gestione aggiuntiva necessaria per aggiornare gli indici su insert / update e lo spazio extra necessario per memorizzarli, viene sprecata quando metà del potrebbero non abituarsi mai, ma a meno che il DB non rilevi carichi pesanti in scrittura, le prestazioni non puzzeranno male anche con gli indici in eccesso.

Indici specifici per query frequenti che altrimenti sarebbero lenti a causa della scansione di tabelle o indici è generalmente una buona idea, anche se non esagerare in quanto potresti scambiare un problema di prestazioni con un altro. Se definisci [customerId], [dateCreated]un indice, ad esempio, ricorda che il pianificatore di query sarà in grado di utilizzarlo per le query che utilizzerebbero un indice solo [customerId]se presenti. Sebbene l'utilizzo di just [customerId]sarebbe leggermente più efficiente rispetto all'utilizzo dell'indice composto, questo può essere mitigato finendo per avere due indici in competizione per lo spazio nella RAM invece di uno (anche se se l'intero set di lavoro normale si adatta facilmente alla RAM, questa competizione di memoria aggiuntiva potrebbe non essere un problema).


+1; ottime informazioni, in particolare il promemoria (che tendo a dimenticare!) che il pianificatore può utilizzare un indice composto a volte quando necessita solo del primo campo (s) da esso per una query.
Andrew Barber,

6

Per rispondere alla domanda originale, sì, gli indici devono essere progettati attorno alle query , non solo alla tabella . L'ordine dei campi nell'indice è di vitale importanza. Progettare un singolo indice in modo che sia ottimale per più query è più difficile e dovrai fare dei compromessi.

Per quanto riguarda il tuo secondo punto, sì, un sacco di indici su singoli singoli campi è fastidiosamente comune. Lo vedo sempre nel mio ambiente, e di solito è una bandiera rossa per me che il team di sviluppo non ha lavorato con un DBA per progettare indici adeguati.

La mia strategia per la progettazione di indici è di indicizzare:

  • Campi utilizzati in DOVE (in ordine di selettività)
  • Campi utilizzati in ORDER BY
  • Includere altri campi (se necessario) per creare un indice di copertura

Quindi, per il tuo esempio:

SELECT [id], [name], [customerId], [dateCreated]
   FROM Representatives WHERE customerId=1 
   ORDER BY dateCreated

Probabilmente progetterei un indice su (CustomerID, dateCreated) INCLUDE (ID, nome). Questo indice di copertura indica che la query non deve mai raggiungere la tabella originale, migliorando notevolmente le prestazioni.

Questo esempio è quasi troppo semplice, però. Un indice ingenuo su just (CustomerID) avrebbe quasi lo stesso effetto (supponendo che ogni cliente abbia un solo rappresentante, quindi sarà richiesta solo una ricerca di un singolo segnalibro nella tabella). Potrebbe anche essere utile eseguire effettivamente un indice cluster su (CustomerID, ID), a seconda di quali altre query vengono eseguite sulla tabella.


+1 per "gli indici devono essere progettati attorno alle query, non solo alla tabella" e al resto della risposta, come notare che l'esempio è molto semplice.
Andrew Barber,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.