Indici MySQL: quali sono le migliori pratiche?


208

Sto usando gli indici sui miei database MySQL da un po 'di tempo ma non li ho mai imparati correttamente . Generalmente metto un indice su tutti i campi che cercherò o selezionerò usando una WHEREclausola ma a volte non sembra così bianco e nero.

Quali sono le migliori pratiche per gli indici MySQL?

Situazioni / dilemmi di esempio:

  • Se una tabella ha sei colonne e tutte sono ricercabili, devo indicizzarle tutte o nessuna?

  • Quali sono gli impatti negativi sulle prestazioni dell'indicizzazione?

  • Se ho una colonna VARCHAR 2500 ricercabile da parti del mio sito, dovrei indicizzarla?


5
Probabilmente dovresti ripetere la domanda. La scelta degli indici è una parte importante per l'ottimizzazione di qualsiasi modello di database. E dal mio punto di vista estraneo al php.
VGE


Risposte:


242

Dovresti assolutamente dedicare un po 'di tempo a leggere l'indicizzazione, c'è molto scritto su di esso ed è importante capire cosa sta succedendo.

In generale, un indice impone un ordinamento sulle righe di una tabella.

Per semplicità, immagina che una tabella sia solo un grosso file CSV. Ogni volta che viene inserita una riga, viene inserita alla fine . Quindi l'ordinamento "naturale" della tabella è solo l'ordine in cui sono state inserite le righe.

Immagina di avere quel file CSV caricato in un'applicazione di foglio di calcolo molto rudimentale. Tutto ciò che fa questo foglio di calcolo è visualizzare i dati e numerare le righe in ordine sequenziale.

Ora immagina di dover trovare tutte le righe con un valore "M" nella terza colonna. Dato ciò che hai a disposizione, hai solo un'opzione. Si esegue la scansione della tabella controllando il valore della terza colonna per ogni riga. Se hai molte righe, questo metodo (una "scansione della tabella") può richiedere molto tempo!

Ora immagina che oltre a questa tabella, hai un indice. Questo indice particolare è l'indice dei valori nella terza colonna. L'indice elenca tutti i valori della terza colonna, in un ordine significativo (diciamo, in ordine alfabetico) e per ciascuno di essi, fornisce un elenco di numeri di riga in cui appare quel valore.

Ora hai una buona strategia per trovare tutte le righe in cui il valore della terza colonna è "M". Ad esempio, è possibile eseguire una ricerca binaria ! Mentre la scansione della tabella richiede di guardare N righe (dove N è il numero di righe), la ricerca binaria richiede solo di guardare le voci dell'indice log-n, nel caso peggiore. Wow, questo è sicuramente molto più semplice!

Naturalmente, se si dispone di questo indice e si stanno aggiungendo righe alla tabella (alla fine, poiché è così che funziona la nostra tabella concettuale), è necessario aggiornare l'indice ogni volta. Quindi fai un po 'più di lavoro mentre scrivi nuove righe, ma risparmi un sacco di tempo quando cerchi qualcosa.

Quindi, in generale, l'indicizzazione crea un compromesso tra efficienza di lettura ed efficienza di scrittura. Senza indici, gli inserimenti possono essere molto veloci: il motore di database aggiunge solo una riga alla tabella. Quando si aggiungono indici, il motore deve aggiornare ciascun indice durante l'esecuzione dell'inserimento.

D'altra parte, le letture diventano molto più veloci.

Speriamo che copra le tue prime due domande (come hanno già risposto gli altri - devi trovare il giusto equilibrio).

Il tuo terzo scenario è un po 'più complicato. Se stai usando LIKE, i motori di indicizzazione in genere ti aiuteranno con la tua velocità di lettura fino al primo "%". In altre parole, se si sta selezionando DOVE COME la colonna "pippo% bar%", il database utilizzerà l'indice per trovare tutte le righe in cui la colonna inizia con "pippo", quindi è necessario eseguire la scansione del set di righe intermedio per trovare il sottoinsieme che contiene "bar". SELEZIONA ... DOVE LA colonna COME '% bar%' non può usare l'indice. Spero che tu possa capire perché.

Infine, è necessario iniziare a pensare agli indici su più di una colonna. Il concetto è lo stesso e si comporta in modo simile alle cose LIKE - essenzialmente, se si dispone di un indice su (a, b, c), il motore continuerà a utilizzare l'indice da sinistra a destra nel miglior modo possibile. Quindi una ricerca nella colonna a potrebbe usare l'indice (a, b, c), come farebbe per una (a, b). Tuttavia, il motore dovrebbe eseguire una scansione completa della tabella se si cercasse DOVE b = 5 AND c = 1)

Spero che questo aiuti a far luce, ma devo ribadire che è meglio spendere qualche ora a cercare buoni articoli che spieghino queste cose in profondità. È anche una buona idea leggere la documentazione del tuo particolare database server. Il modo in cui gli indici vengono implementati e utilizzati dai pianificatori di query può variare in modo abbastanza ampio.


10
E gli FULLTEXTindici? Possono aiutare con condizioni come LIKE '%bar%'?
Settagramma

2
@Septagram - FULLTEXTpuò aiutare con quella query se bar è una "parola". FULLTEXTgestisce le parole, non sottostringhe arbitrarie (come LIKEfa).
Rick James,

@timdev esplicitamente in quale parte è stata data risposta alla prima domanda? Riesco a rilevare la seconda e la terza domanda a cui hanno risposto la prima e la seconda parte (prima e dopo di Spero che copra le tue prime due domande ) della tua preziosa risposta
Manuel Jordan,

1
@ManuelJordan - Non c'è una risposta semplice alla prima domanda. Dipende da come si desidera bilanciare i compromessi nel contesto dell'uso previsto (o anche meglio, osservato).
timdev,

57

Dai un'occhiata a presentazioni come More Mastering the Art of Indexing .

Aggiornamento 12/2012: ho pubblicato una mia nuova presentazione: Come progettare gli indici, davvero . L'ho presentato nell'ottobre 2012 allo ZendCon di Santa Clara e nel dicembre 2012 al Percona Live London.

La progettazione degli indici migliori è un processo che deve corrispondere alle query eseguite nella tua app.

È difficile raccomandare qualsiasi regola generale su quali colonne siano le migliori da indicizzare o se si dovrebbero indicizzare tutte le colonne, nessuna colonna, quali indici dovrebbero estendersi su più colonne, ecc. Dipende dalle query che è necessario eseguire.

Sì, esiste un certo sovraccarico, quindi non è necessario creare indici inutilmente. Ma dovresti creare gli indici che danno beneficio alle query che devi eseguire rapidamente. L'overhead di un indice è di solito ampiamente compensato dai suoi benefici.

Per una colonna che è VARCHAR (2500), probabilmente si desidera utilizzare un indice FULLTEXT o un indice prefisso:

CREATE INDEX i ON SomeTable(longVarchar(100));

Nota che un indice convenzionale non può aiutarti se stai cercando parole che potrebbero trovarsi nel mezzo di quel lungo varchar. Per questo, usa un indice full-text.


3
Grazie mille. slideshare.net/matsunobu/… è stato davvero molto utile.
Bishal Paudel,



1
Incredibile presentazione (quella del 2012), ho davvero capito tutto il punto degli indici.
DarkteK

46

Non ripeterò alcuni dei buoni consigli in altre risposte, ma aggiungerò:

Indici composti

Puoi creare indici composti, un indice che include più colonne. MySQL può usarli da sinistra a destra . Quindi se hai:

Table A
Id
Name
Category
Age
Description

se si dispone di un indice composto che include Nome / Categoria / Età in quell'ordine, queste clausole WHERE utilizzerebbero l'indice:

WHERE Name='Eric' and Category='A'

WHERE Name='Eric' and Category='A' and Age > 18

ma

WHERE Category='A' and Age > 18

non userebbe quell'indice perché tutto deve essere usato da sinistra a destra.

Spiegare

Usa Spiega / Spiega esteso per capire quali indici sono disponibili per MySQL e quale seleziona effettivamente. MySQL utilizzerà solo UNA chiave per query .

EXPLAIN EXTENDED SELECT * from Table WHERE Something='ABC'

Registro query lento

Attiva il registro delle query lente per vedere quali query sono lente.

Colonne larghe

Se hai una colonna larga in cui la maggior parte della distinzione si verifica nei primi diversi caratteri, puoi usare solo i primi N caratteri nel tuo indice. Esempio: abbiamo una colonna ReferenceNumber definita come varchar (255) ma il 97% dei casi, il numero di riferimento è di 10 caratteri o meno. Ho cambiato l'indice per guardare solo i primi 10 caratteri e ho migliorato un po 'le prestazioni.


Ho una domanda sull'ultima parte. Ho letto da qualche parte che se crei una colonna con VARCHAR dovresti sempre impostarla su 255. Ora hai detto che un indice impostato su questo tipo di colonna potrebbe limitarsi a guardare solo i primi 10 caratteri. Come puoi esattamente farlo?
AlexioVay

20

Se una tabella ha sei colonne e tutte sono ricercabili, dovrei indicizzarle tutte o nessuna

Stai cercando su un campo per campo o alcune ricerche utilizzano più campi? Su quali campi vengono maggiormente cercati? Quali sono i tipi di campo? (L'indice funziona meglio su INT che su VARCHAR per esempio) Hai provato a usare EXPLAIN sulle query che vengono eseguite?

Quali sono gli impatti negativi sulle prestazioni dell'indicizzazione

AGGIORNAMENTI e INSERTI saranno più lenti. Ci sono anche i requisiti di spazio di archiviazione aggiuntivo, ma al giorno d'oggi non è importante.

Se ho una colonna VARCHAR 2500 che è ricercabile da parti del mio sito, dovrei indicizzarla

No, a meno che non sia UNIQUE (il che significa che è già indicizzato) o cerchi solo corrispondenze esatte su quel campo (non usando LIKE o la ricerca full-text di mySQL).

Generalmente metto un indice su tutti i campi che cercherò o selezionerò usando una clausola WHERE

Normalmente indicizzerei i campi che sono i più interrogati, e quindi INT / BOOLEAN / ENUM piuttosto che i campi che sono VARCHAR. Non dimenticare, spesso è necessario creare un indice su campi combinati, piuttosto che un indice su un singolo campo. Utilizzare EXPLAIN e controllare il registro lento.


11

Carica i dati in modo efficiente : gli indici accelerano i recuperi ma rallentano gli inserimenti e le eliminazioni, nonché gli aggiornamenti dei valori nelle colonne indicizzate. Cioè, gli indici rallentano la maggior parte delle operazioni che prevedono la scrittura. Ciò si verifica perché la scrittura di una riga richiede la scrittura non solo della riga di dati, ma richiede anche modifiche a tutti gli indici. Più indici ha una tabella, più modifiche devono essere apportate e maggiore è il degrado medio delle prestazioni. La maggior parte delle tabelle riceve molte letture e poche scritture, ma per una tabella con un'alta percentuale di scritture, il costo dell'aggiornamento dell'indice potrebbe essere significativo.

Evita gli indici : se non hai bisogno di un indice specifico per migliorare il rendimento delle query, non crearlo.

Spazio su disco : un indice occupa spazio su disco e più indici occupano corrispondentemente più spazio. Ciò potrebbe farti raggiungere un limite di dimensioni della tabella più rapidamente rispetto a se non ci sono indici. Evita gli indici ove possibile.

Takeaway: non sovraindicare


5

In generale, gli indici aiutano a velocizzare la ricerca nel database, con lo svantaggio di utilizzare spazio su disco aggiuntivo e rallentare INSERT/ UPDATE/ DELETEquery. Usa EXPLAINe leggi i risultati per scoprire quando MySQL usa i tuoi indici.

Se una tabella ha sei colonne e tutte sono ricercabili, devo indicizzarle tutte o nessuna?

L'indicizzazione di tutte e sei le colonne non è sempre la migliore pratica.

(a) Utilizzerai una di quelle colonne durante la ricerca di informazioni specifiche?

(b) Qual è la selettività di quelle colonne (quanti valori distinti sono memorizzati, rispetto alla quantità totale di record nella tabella)?

MySQL utilizza un ottimizzatore basato sui costi, che tenta di trovare il percorso "più economico" durante l'esecuzione di una query. E i campi con bassa selettività non sono buoni candidati.

Quali sono gli impatti negativi sulle prestazioni dell'indicizzazione?

Già risposto: spazio su disco aggiuntivo, prestazioni inferiori durante l'inserimento - aggiornamento - eliminazione.

Se ho una colonna VARCHAR 2500 che è ricercabile da parti del mio sito, dovrei indicizzarla?

Prova l' indice FULLTEXT .


4

1/2) Gli indici accelerano determinate operazioni di selezione ma rallentano altre operazioni come l'inserimento, l'aggiornamento e l'eliminazione. Può essere un buon equilibrio.

3) usa un indice full text o forse sfinge


Per evitare che slow down other operations like insert, update and deletestu possa usare START TRANSACTION; YOUR CODE HERE; COMMIT Quale può aiutare ad evitare slowing downle altre operazioni, in quanto controllerà una sola volta i vincoli. CAVEAT: Se si utilizza REPLACE INTOe SQL_MODE<> STRICT_ALL_TABLESO TRADITIONALThe Bulk Loadignorerà la sostituzione e inserirà i duplicati.
JayRizzo,

Le transazioni non sono supportate in tutti i motori MySQL. AFAIK, le transazioni rallentano le operazioni sui DB, anche se vengono utilizzate solo implicitamente. Ciò di cui abbiamo bisogno per progettare in base alle prestazioni effettive è un modo semiautomatico di profilare (misurare le prestazioni) di varie scelte di ottimizzazione, inclusi indici e transazioni.
David Spector,
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.