2012-04-13 7 views
19

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 
+0

Haben Sie etwas dagegen, die Abfrage auch zu zeigen? –

+0

@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

+0

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. –

Antwort

13

Hängt davon ab, was Sie vorhaben, und was die Abfrage ist.

Im Allgemeinen müssen Sie für jede Zeile in EXPLAIN, die eine Using where hat, einen Index verwenden (possible keys und keys Spalte). Dies sind Ihre Filter und beinhalten WHERE und ON. Es zu sagen, Using index ist noch besser. Es bedeutet, dass es einen überdeckenden Index gibt, und MySQL kann die Daten direkt aus dem Index abrufen, anstatt die Zeile in den Tabellendaten aufzurufen.

Die Linien, wo es keine Using where gibt, und es wird eine große Anzahl von Zeilen zurückgeben, sollten betrachtet werden.Diese geben Werte für alle Zeilen in der Tabelle zurück. Ich weiß nicht, was deine Anfrage ist, also weiß ich nicht, ob ich hier etwas zu befürchten habe. Versuchen Sie, die Ergebnismenge zu filtern, um die Größe zu reduzieren und die Leistung zu verbessern.

Sie sollten im Allgemeinen versuchen zu vermeiden, Using filesort oder Using temporary zu sehen, obwohl diese nur schlecht sind, wenn Sie sie nicht erwarten.

Filesort wird normalerweise mit der ORDER-Klausel angezeigt. Normalerweise sollte MySQL einen überdeckenden Index (Using index) verwenden, damit die Zeilen vom Server in der Reihenfolge zurückgegeben werden. Wenn dies nicht der Fall ist, muss MySQL sie anschließend mithilfe von filesort bestellen.

Using temporary kann schlecht sein, wenn es sich auf abgeleitete Tabellen bezieht, da sie keine Indizes haben. Es scheint, dass Sie eine temporäre Tabelle mit Indizes explizit erstellt haben, also hier ist es nicht schlecht. Manchmal ist Ihre einzige Wahl die Verwendung einer abgeleiteten Tabelle und daher Using temporary.

+0

Danke Marcus. Was ich am seltsamsten finde, ist der signifikante Unterschied in der Leistung, der sich aus einem Filter am Finaltisch ergibt; daher scheint es, dass das Problem nicht in den "Zeilen, wo ... es ist eine große Anzahl von Zeilen zurückgibt", dass Sie vorschlagen, dass ich sehe? – eggyal

Verwandte Themen