Osservando il piano EXPLAIN
di una query, come si determina dove è possibile ottimizzare meglio le ottimizzazioni?Come ottimizzare le query MySQL in base al piano EXPLAIN
Apprezzo che una delle prime cose da verificare è se vengono utilizzati buoni indici, ma oltre a ciò sono un po 'perplesso. Attraverso prove ed errori, in passato, ho scoperto che l'ordine in cui vengono condotti i join può essere una buona fonte di miglioramento, ma come si può determinare ciò guardando il piano di esecuzione?
Mentre mi piacerebbe molto avere una buona comprensione generale su come ottimizzare le query (lettura consigliata molto apprezzata!), Mi rendo anche conto che è spesso più facile discutere casi concreti che parlare in astratto. Dal momento che sto attualmente sbattere la testa contro il muro con questo, i vostri pensieri sarebbe molto apprezzato:
id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE S const PRIMARY,l,p,f4 PRIMARY 2 const 1 Using temporary 1 SIMPLE Q ref PRIMARY,S S 2 const 204 Using index 1 SIMPLE V ref PRIMARY,n,Q Q 5 const,db.Q.QID 6 Using where; Using index; Distinct 1 SIMPLE R1 ref PRIMARY,L L 154 const,db.V.VID 447 Using index; Distinct 1 SIMPLE W eq_ref PRIMARY,w PRIMARY 5 const,db.R.RID,const 1 Using where; Distinct 1 SIMPLE R2 eq_ref PRIMARY,L PRIMARY 156 const,db.W.RID,const 1 Using where; Distinct
Sono corretto interpretare la riga finale del piano di esecuzione come segue:
- come è completamente abbinato alla sua chiave primaria, solo una riga di
R2
deve essere recuperata per riga di output; - tuttavia, tali righe di output vengono quindi filtrate in base a determinati criteri applicabili a
R2
?
Se è così, il mio problema sta nel filtraggio che si verifica in quella fase finale. Se la condizione non provoca alcun filtraggio (ad esempio WHERE `Col_1_to_3` IN (1,2,3)
), la query viene eseguita estremamente rapidamente (~ 50 ms); tuttavia, se la condizione limita le righe selezionate (WHERE `Col_1_to_3` IN (1,2)
), la query impiega molto più tempo (~ 5 s). Se la restrizione è relativa a una singola corrispondenza (WHERE `Col_1_to_3` IN (1)
), l'ottimizzatore suggerisce un piano di esecuzione completamente diverso (che ha un margine leggermente migliore di 5, ma ancora molto inferiore a 50 ms). Non sembra che ci sia un indice migliore che può essere usato su quella tabella (dato che usa già la chiave primaria per restituire una riga per risultato?).
Come si dovrebbero interpretare tutte queste informazioni? Ho ragione nel ritenere che, poiché tale filtraggio degli output sta avvenendo sul tavolo finale da unire, si spreca uno sforzo considerevole contro l'adesione alla tabella precedente e il filtraggio di tali file prima? In tal caso, in che modo si determina quando è necessario unire il piano di esecuzione R2
?
Mentre io resistito compreso lo schema di query & per intero qui (come mi sarebbe davvero in grado di conoscere che cosa cercare, non solo essere detto la risposta), ho capito che è necessaria per far progredire la discussione:
SELECT DISTINCT
`Q`.`QID`
FROM
`S`
NATURAL JOIN `Q`
NATURAL JOIN `V`
NATURAL JOIN `R` AS `R1`
NATURAL JOIN `W`
JOIN `R` AS `R2` ON (
`R2`.`SID` = `S`.`SID`
AND `R2`.`RID` = `R1`.`RID`
AND `R2`.`VID` = `S`.`V_id`
AND `R2`.`Col_1_to_3` IN (1,2) -- this is where performance suffers!
)
WHERE
AND `S`.`SID` = @x
AND `W`.`WID` = @y
;
la definizione di tabella R
è:
CREATE TABLE `R` (
`SID` smallint(6) unsigned NOT NULL,
`RID` smallint(6) unsigned NOT NULL,
`VID` varchar(50) NOT NULL DEFAULT '',
`Col_1_to_3` smallint(1) DEFAULT NULL,
`T` varchar(255) DEFAULT NULL,
PRIMARY KEY (`SID`,`RID`,`VID`),
KEY `L` (`SID`,`VID`,`Col_1_to_3`),
CONSTRAINT `R_f1` FOREIGN KEY (`SID`) REFERENCES `S` (`SID`),
CONSTRAINT `R_f2` FOREIGN KEY (`SID`, `VID`) REFERENCES `V` (`SID`, `VID`),
CONSTRAINT `R_f3` FOREIGN KEY (`SID`, `VID`, `Col_1_to_3`) REFERENCES `L` (`SID`, `VID`, `LID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
Ti dispiace mostrare anche la query? –
@MarcusAdams: Non mi dispiace *, ma cosa vorresti cercare? Sento che probabilmente imparerò di più se sapessi cosa vedresti ... – eggyal
Ti riferisci a col_1_to_3, ma non vedo una colonna di questo tipo nel risultato di EXPLAIN. Se riesci a formulare la domanda in modo che riguardi solo la spiegazione, in altre parole rimuovi i paragrafi che parlano della query, allora non abbiamo bisogno della query e la risposta è sì. In generale, abbiamo bisogno della query, dello schema e della spiegazione, altrimenti indovineremo. –