So che posso cambiare il modo in cui MySQL esegue una query utilizzando la parola chiave FORCE INDEX (abc)
. Ma c'è un modo per cambiare l'ordine di esecuzione?Esiste un modo per forzare l'ordine di esecuzione MySQL?
La mia domanda si presenta in questo modo:
SELECT c.*
FROM table1 a
INNER JOIN table2 b ON a.id = b.table1_id
INNER JOIN table3 c ON b.itemid = c.itemid
WHERE a.itemtype = 1
AND a.busy = 1
AND b.something = 0
AND b.acolumn = 2
AND c.itemid = 123456
ho una chiave per ogni relazione/vincolo che uso. Se corro spiegare su questa affermazione, vedo che mysql inizia a interrogare c prima.
id select_type table type
1 SIMPLE c ref
2 SIMPLE b ref
3 SIMPLE a eq_ref
Tuttavia, so che l'interrogazione in ordine a -> b -> c
sarebbe più veloce (ho dimostrato che) C'è un modo per dire a MySQL di utilizzare un ordine specifico?
Aggiornamento: È così che so che a -> b -> c
è più veloce.
La query precedente richiede 1,9 secondi per essere completata e restituisce 7 righe. Se cambio la query per
SELECT c.*
FROM table1 a
INNER JOIN table2 b ON a.id = b.table1_id
INNER JOIN table3 c ON b.itemid = c.itemid
WHERE a.itemtype = 1
AND a.busy = 1
AND b.something = 0
AND b.acolumn = 2
HAVING c.itemid = 123456
della query di 0,01 secondi (Senza usare avente ottengo 10.000 righe). Tuttavia questa non è una soluzione elegante perché questa query è un esempio semplificato. Nel mondo reale mi sono unito da c ad altri tavoli. Dal momento che HAVING
è un filtro che viene eseguito sull'intero risultato, significherebbe che potrei estrarre alcuni record più dal db che da quello necessario.
Edit2: Solo alcune informazioni:
- La parte variabile in questa query è c.itemid. Tutto il resto sono valori fissi che non cambiano.
- indici sono installati bene e MySQL sceglie quelle giuste per me
- tra A e B c'è un 1: n relazione (indice primario è utilizzato)
- tra B e C non v'è una relazione molti a molti relazione (indice IDX_ITEMID viene utilizzato)
il punto è che mysql dovrebbe iniziare interrogazione della tabella ae lavorare è modo giù a c e non viceversa. Qualsiasi cambiamento per ottenere quello.
Soluzione: Non è esattamente quello che volevo, ma questo sembra funzionare:
SELECT c.*
FROM table1 a
INNER JOIN table2 b ON a.id = b.table1_id
INNER JOIN table3 c ON b.itemid = c.itemid
WHERE a.itemtype = 1
AND a.busy = 1
AND b.something = 0
AND b.acolumn = 2
AND c.itemid = 123456
AND f.id IN (
SELECT DISTINCT table2.id FROM table1
INNER JOIN table2 ON table1.id = table2.table1_id
WHERE table1.itemtype = 1 AND table1.busy = 1)
Come hai dimostrato che 'a -> b -> c' sarebbe più veloce? Inoltre, puoi mostrare i tuoi indici? – Unreason
Per quanto riguarda i test che sono più veloci, può essere difficile verificarlo senza avere una grande quantità di dati pre-caricati e simulando un carico normale. Spesso è bene lasciare che MySQL faccia la propria ottimizzazione, che diventa sempre più accurata più dati si hanno (e nel tempo, o si esegue ANALYZE TABLE una o due volte), e si forzano solo gli indici se si incontrano problemi. Tali problemi esistono però; Ho sicuramente avuto situazioni in cui il piano di query di MySQL era patologicamente negativo ma dopo aver forzato un certo indice e quindi unirmi all'ordine, ha funzionato in modo efficiente. – thomasrutter
@thomasrutter: Se l'ottimizzazione di MySQL risulta in una query 2-7 sec (dipende dal carico/quantità di dati) non ho altra scelta che usare le mie ottimizzazioni :) AS Hammerite ha suggerito: STRAIGHT_JOIN fa ciò che voglio e 1 ha fissato la query migliaia di volte. –