Indice di copertura utilizzato nonostante la colonna mancante


8

Ho la seguente query, usando MariaDB 10 / InnoDB:

SELECT id, sender_id, receiver_id, thread_id, date_created, content 
FROM user_message 
WHERE thread_id = 12345 
  AND placeholder = FALSE
ORDER BY date_created DESC 
LIMIT 20

Questa query recupera i messaggi in base alle condizioni indicate e ordina per data di creazione.

Ho un indice di copertura sopra (thread_id, date_created).

Quando eseguo EXPLAIN, viene utilizzato l'indice corretto e ottengo l'output "Uso di dove", sebbene la query stia utilizzando una colonna nel mezzo dell'istruzione che non è nell'indice. Posso usare qualsiasi valore per "segnaposto = x" e il risultato è lo stesso.

Se cambio l'ordinamento per utilizzare un'altra colonna, EXPLAIN indica correttamente "Uso di dove. Uso di filesort".

Sto avendo un momento graffiante. Qualcuno potrebbe far luce su questo? Quello che mi aspetterei di vedere è che sarebbe necessario un ulteriore assortimento di file poiché l'indice di copertura non può essere utilizzato completamente a causa della colonna aggiuntiva.

Risposte:


8

Caso A
Query:

WHERE thread_id = 12345 
  AND placeholder = FALSE
ORDER BY some_column DESC 
LIMIT 20

Indice:

(thread_id, date_created)

Piano:

Index is used
Using Where
Using filesort

Nessun problema, vero? Se viene utilizzato l'indice (per abbinare parzialmente la WHEREcondizione), abbiamo ancora bisogno di un'operazione di ordinamento per ordinare i risultati per some_column(che non è nell'indice). È inoltre necessario un controllo aggiuntivo (Utilizzo di Where) per mantenere anche solo le righe che corrispondono alla seconda condizione. OK.


Caso B (la domanda)
Query:

WHERE thread_id = 12345 
  AND placeholder = FALSE
ORDER BY date_created DESC 
LIMIT 20

Indice:

(thread_id, date_created)

Piano:

Index is used
Using Where
-- no "Using filesort"

Quindi, perché non ha bisogno di una sorta qui ? Perché l'indice è sufficiente per ordinare come vuole la query. Esiste ovviamente il problema aggiuntivo della condizione aggiuntiva ( AND placeholder = FALSE) che non è coperta dall'indice.

OK ma non abbiamo davvero bisogno di una specie qui. L'indice può fornirci risultati che corrispondono alla prima condizione ( WHERE thread_id = 12345) e sono nell'ordine desiderato per l'output. L'unico controllo aggiuntivo di cui abbiamo bisogno - e ciò che fa il piano - è quello di ottenere le righe dalla tabella, nell'ordine fornito dall'indice, e controllare questa seconda condizione fino a quando non otteniamo 20 corrispondenze. Questo è ciò che significa "Using Where" ".

Potremmo ottenere le 20 partite nelle prime 20 righe (quindi davvero buone e veloci) o nelle prime 100 (ancora probabilmente abbastanza veloci) o nelle prime 1000000 (probabilmente molto, molto lente) o potremmo ottenere solo 19 partite dal tabella anche dopo aver letto tutte le righe corrispondenti dall'indice (davvero molto lento su una grande tabella). Tutto dipende dalla distribuzione dei dati.


Caso C (piano ancora migliore)
Query:

WHERE thread_id = 12345 
  AND placeholder = FALSE
ORDER BY date_created DESC 
LIMIT 20

Indice:

(placeholder, thread_id, date_created)

Piano:

Index is used
-- no "Using Where"
-- no "Using filesort"

Ora il nostro indice corrisponde a entrambe le condizioni e l'ordine per. Il piano è piuttosto semplice: ottieni le prime * 20 corrispondenze dall'indice e leggi le righe corrispondenti dalla tabella. Nessun controllo extra (nessun "utilizzo di Where") e nessun ordinamento (nessun "utilizzo di filesort") necessario.

primo *: i primi 20 quando si legge l'indice all'indietro dalla fine (come abbiamo fatto ORDER BY .. DESC) ma non è un problema. Gli indici B-tree possono essere letti in avanti e indietro con prestazioni quasi uguali.


7
  • Utilizzando indice indica un " copertura indice" - Tutte le colonne ovunque nel SELECTsono ovunque nell'indice uno. Quindi, non hai un indice "di copertura". E non è pratico creare un indice di copertura per la tua query (troppe colonne menzionate).
  • Usando dove - principalmente rumore.
  • Utilizzo di filesort : la query necessita di un ordinamento, ma potrebbe trovarsi nella RAM o in una tabella temporanea. E potrebbero esserci più tipi (ad es. GROUP BY x ORDER BY b)
  • Ognuno di questi consentirà di guardare solo 20 righe; qualsiasi altro indice richiederà di toccare più righe, possibilmente l'intera tabella:

    INDEX(thread_id, placeholder, date_created)
    INDEX(placeholder, thread_id, date_created)
  • No, la cardinalità dei componenti di un indice composito non ha importanza quando si ordinano le colonne nell'indice.

Il mio ricettario spiega come ricavare l'indice ottimale, dato a SELECT.


Grazie per il libro di cucina - foglio molto bello.
Tom,
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.