Mit Blick auf eine Abfrage EXPLAIN
Plan, wie bestimmt man, wo Optimierungen am besten vorgenommen werden können?Wie optimiert man MySQL Abfragen basierend auf EXPLAIN Plan
Ich weiß, dass eine der ersten Dinge zu prüfen ist, ob gute Indizes verwendet werden, aber darüber hinaus bin ich ein wenig ratlos. Durch Versuch und Irrtum in der Vergangenheit habe ich manchmal festgestellt, dass die Reihenfolge, in der Joins durchgeführt werden, eine gute Quelle für Verbesserungen sein kann, aber wie kann man das anhand des Ausführungsplans feststellen?
Während ich gerne ein gutes allgemeines Verständnis für die Optimierung von Suchanfragen gewinnen würde (das vorgeschlagene Lesen wird sehr geschätzt!), Fällt mir auch auf, dass es oft einfacher ist, konkrete Fälle zu diskutieren, als abstrakt zu sprechen. Da ich zur Zeit mit dieser meinen Kopf gegen die Wand am hämmern würde Ihre Gedanken sehr geschätzt:
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
Bin ich bei der Interpretation der letzten Reihe des Ausführungsplans wie folgt korrigieren:
- als es ist vollständig auf seinen Primärschlüssel abgestimmt, nur eine Zeile von
R2
muss pro Ausgabezeile abgerufen werden; - jedoch werden solche Ausgabezeilen dann anhand einiger Kriterien gefiltert, die für
R2
gelten?
Wenn ja, liegt mein Problem bei der Filterung, die in diesem letzten Schritt erfolgt. Wenn die Bedingung zu keiner Filterung führt (z. B. WHERE `Col_1_to_3` IN (1,2,3)
), wird die Abfrage extrem schnell ausgeführt (~ 50 ms); Wenn die Bedingung jedoch die ausgewählten Zeilen einschränkt (WHERE `Col_1_to_3` IN (1,2)
), dauert die Abfrage erheblich länger (~ 5s). Wenn die Beschränkung auf eine einzige Übereinstimmung (WHERE `Col_1_to_3` IN (1)
) beschränkt ist, schlägt der Optimierer einen völlig anderen Ausführungsplan vor (der geringfügig bessere Ergebnisse erzielt als 5s, aber immer noch viel schlechter als 50ms). Es scheint nicht, dass es einen besseren Index gibt, der für diese Tabelle verwendet werden kann (vorausgesetzt, dass der Primärschlüssel bereits vollständig verwendet wird, um eine Zeile pro Ergebnis zurückzugeben?).
Wie soll man all diese Informationen interpretieren? Habe ich recht, wenn ich bedenke, dass, weil eine solche Ausgabefilterung an der Final Table stattfindet, um verbunden zu werden, ein erheblicher Aufwand im Vergleich zu früherem Verknüpfen mit der Tabelle und schnellerem Filtern solcher Zeilen verschwendet wird? Wenn ja, wie bestimmt man, wann im Ausführungsplan R2
verbunden werden soll?
Während ich widerstanden, einschließlich der Abfrage & Schema vollständig hier (wie ich würde wirklich wahrscheinlich zu wissen, was zu suchen, nicht nur die Antwort gesagt werden), ich verstehe, es ist notwendig, um die Diskussion voranzubringen:
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
;
R
die Definition der Tabelle ist:
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
Haben Sie etwas dagegen, die Abfrage auch zu zeigen? –
@MarcusAdams: Ich weiß nicht *, aber was würdest du suchen? Ich habe das Gefühl, dass ich wahrscheinlich mehr darüber lernen würde, wenn ich wüsste, was Sie sich ansehen würden ... – eggyal
Sie verweisen auf col_1_to_3, aber ich sehe keine solche Spalte im EXPLAIN-Ergebnis. Wenn Sie die Frage so formulieren können, dass es nur um die Erklärung geht, also die Absätze entfernen, die über die Abfrage sprechen, dann brauchen wir die Abfrage nicht, und die Antwort ist ja. Im Allgemeinen brauchen wir die Abfrage, das Schema und das Explain, ansonsten raten wir. –