Come si fa a far utilizzare a MySQL un indice per una query di visualizzazione? La risposta breve, fornire un indice che MySQL può utilizzare.
In questo caso, l'indice ottimale è probabilmente un indice di "copertura":
... ON highscores (player, happened_in, score)
È probabile che MySQL utilizzerà quell'indice e EXPLAIN mostrerà:"Using index"
a causa del WHERE player = 24
(un predicato di uguaglianza sulla colonna iniziale dell'indice. Il GROUP BY happened_id
(la seconda colonna nell'indice), può consentire a MySQL di ottimizzarlo utilizzando l'indice per evitare un'operazione di ordinamento. Compreso il score
colonna nell'indice consentirà alla query di essere soddisfatta interamente dall'indice, senza dover visitare (cercare) le pagine di dati a cui fa riferimento l'indice.
Questa è la risposta rapida. La risposta più lunga è che è molto improbabile che MySQL utilizzi un indice con la colonna iniziale di happened_id
per la query di visualizzazione.
Perché la vista causa un problema di prestazioni
Uno dei problemi che hai con la vista MySQL è che MySQL non "spinge" il predicato dalla query esterna alla query della vista.
La tua query esterna specifica WHERE happened_in = 2006
. L'ottimizzatore MySQL non considera il predicato quando esegue la "query di visualizzazione" interna. Quella query per la vista viene eseguita separatamente, prima della query esterna. Il set di risultati dall'esecuzione di quella query viene "materializzato"; ovvero, i risultati vengono archiviati come una tabella MyISAM intermedia. (MySQL la chiama "tabella derivata" e il nome che usano ha senso, quando comprendi le operazioni eseguite da MysQL.)
La linea di fondo è che l'indice che hai definito su happened_in
non viene utilizzato da MySQL quando esegue la query che costituisce la definizione della vista.
Dopo aver creato la "tabella derivata" intermedia, ALLORA viene eseguita la query esterna, utilizzando quella "tabella derivata" come origine riga. È quando viene eseguita la query esterna che happened_in = 2006
viene valutato il predicato.
Nota che tutte le righe della query di visualizzazione sono archiviate, che (nel tuo caso) è una riga per OGNI valore di happened_in
, non solo quello su cui specifichi un predicato di uguaglianza nella query esterna.
Il modo in cui vengono elaborate le query di visualizzazione potrebbe essere "inaspettato" da alcuni, e questo è uno dei motivi per cui l'utilizzo di "viste" in MySQL può portare a problemi di prestazioni, rispetto al modo in cui le query di visualizzazione vengono elaborate da altri database relazionali.
Miglioramento delle prestazioni della query di visualizzazione con un indice di copertura adeguato
Data la definizione della tua vista e la tua query, il meglio che otterrai sarebbe un metodo di accesso "Uso dell'indice" per la query della vista. Per ottenerlo, avresti bisogno di un indice di copertura, ad es.
... ON highscores (player, happened_in, score).
È probabile che questo sia l'indice più vantaggioso (dal punto di vista delle prestazioni) per la definizione della vista esistente e la query esistente. Il player
column è la colonna iniziale perché hai un predicato di uguaglianza su quella colonna nella query di visualizzazione. Il happened_in
colonna è successiva, perché hai un'operazione GROUP BY su quella colonna e MySQL sarà in grado di utilizzare questo indice per ottimizzare l'operazione GROUP BY. Includiamo anche il score
colonna, perché questa è l'unica altra colonna a cui si fa riferimento nella query. Ciò rende l'indice un indice di "copertura", perché MySQL può soddisfare quella query direttamente dalle pagine dell'indice, senza la necessità di visitare le pagine della tabella sottostante. E questo è ottimo per uscire da quel piano di query:"Uso di indice" senza "Uso di filesort".
Confronta le prestazioni con query standalone senza tabella derivata
Puoi confrontare il piano di esecuzione per la tua query con la vista rispetto a una query autonoma equivalente:
SELECT player
, MAX(score) AS highest_score
, happened_in
FROM highscores
WHERE player = 24
AND happened_in = 2006
GROUP
BY player
, happened_in
La query autonoma può anche utilizzare un indice di copertura, ad es.
... ON highscores (player, happened_in, score)
ma senza la necessità di materializzare una tabella MyISAM intermedia.
Non sono sicuro che nessuno dei precedenti fornisca una risposta diretta alla domanda che stavi ponendo.
D:Come posso fare in modo che MySQL utilizzi un INDEX per la query di visualizzazione?
R:Definisci un INDEX adatto che può essere utilizzato dalla query di visualizzazione.
La risposta breve è fornire un "indice di copertura" (l'indice include tutte le colonne a cui si fa riferimento nella query di visualizzazione). Le colonne iniziali di quell'indice dovrebbero essere le colonne a cui si fa riferimento con i predicati di uguaglianza (nel tuo caso, la colonna player
sarebbe una colonna principale perché hai un player = 24
predicato nella query. Inoltre, le colonne a cui si fa riferimento in GROUP BY dovrebbero essere colonne iniziali nell'indice, il che consente a MySQL di ottimizzare GROUP BY
operazione, utilizzando l'indice anziché utilizzare un'operazione di ordinamento.
Il punto chiave qui è che la query di visualizzazione è fondamentalmente una query autonoma; i risultati di quella query vengono archiviati in una tabella "derivata" intermedia (una tabella MyISAM che viene creata quando viene eseguita una query sulla vista.
L'uso delle viste in MySQL non è necessariamente una "cattiva idea", ma raccomanderei vivamente a coloro che scelgono di utilizzare le viste all'interno di MySQL di essere CONSAPEVOLI di come MySQL elabora le query che fanno riferimento a tali viste. E il modo in cui MySQL elabora le query di visualizzazione differisce (in modo significativo) dal modo in cui le query di visualizzazione vengono gestite da altri database (ad es. Oracle, SQL Server).