Mysql
 sql >> Database >  >> RDS >> Mysql

Quando si ordina per data desc, l'utilizzo di una query temporanea rallenta

Penso che la maggior parte dei problemi qui e in domande simili derivi dall'incomprensione di come MySQL (e altri database) utilizzi gli indici per l'ordinamento. La risposta è:MySQL non usa gli indici per l'ordinamento, può semplicemente leggere i dati nell'ordine di un indice o nella direzione opposta. Se ti è capitato di voler ordinare i dati nell'ordine dell'indice attualmente utilizzato, sei fortunato, altrimenti il ​​risultato verrà ordinato (quindi filesort in EXPLAIN)

Questo è l'ordine dell'intero risultato dipende principalmente da quale tabella è stata la prima nel join. E se guardi il tuo EXPLAIN vedrai che il join inizia dalla tabella 'log_codes' (perché è molto più piccola).

Fondamentalmente, ciò di cui hai bisogno è un indice composito (partner_id, data) su 'log_entries', un indice composito di copertura (log_code, category_overview, log_desc) per 'log_codes', cambia 'INNER JOIN' in 'STRAIGHT_JOIN' per forzare l'ordine di unione, e ordina per "data" DESC (fortunatamente anche questo indice coprirà).

UPD1 :Mi dispiace, ho digitato male l'indice per la prima tabella:dovrebbe essere (partner_id, log_code, date) .

MySQL può generare direttamente i dati purché tu sia d'accordo con l'ordine in cui li ottiene, oppure inserire i dati in una tabella temporanea, applicare quindi l'ordinamento e l'output. Quando ordini in base a un campo da qualsiasi tabella non prima nei join, MySQL deve ordinare i dati (non solo l'output nell'ordine di un indice) e per ordinare i dati ha bisogno di una tabella temporanea.

Per produrre le righe 50000,25 MySQL deve comunque recuperare le prime 50000 e saltarle. Dato che ho perso una colonna nell'indice, MySQL non solo ha eseguito lo skan dell'indice, ma per ogni elemento ha effettuato una ricerca aggiuntiva sul disco per log_code valore. Con l'indice di copertura dovrebbe essere molto più veloce, poiché tutti i dati possono essere recuperati dall'indice.

UPD2 :prova a forzare l'indice:

SELECT log_entries.date, log_codes.log_desc
FROM log_entries FORCE INDEX (IX_partner_code_date)
STRAIGHT_JOIN log_codes
  ON log_codes.log_code = log_entries.log_code
WHERE log_entries.partner_id = 1
  AND log_codes.category_overview = 1
ORDER BY log_entries.date DESC;