Wie bringen Sie MySQL dazu, einen Index für eine Ansichtsabfrage zu verwenden? Die kurze Antwort:Geben Sie einen Index an, den MySQL verwenden kann.
In diesem Fall ist der optimale Index wahrscheinlich ein "deckender" Index:
... ON highscores (player, happened_in, score)
Es ist wahrscheinlich, dass MySQL diesen Index verwendet, und das EXPLAIN zeigt:"Using index"
wegen WHERE player = 24
(ein Gleichheitsprädikat für die führende Spalte im Index. Die GROUP BY happened_id
(die zweite Spalte im Index) kann es MySQL ermöglichen, dies mithilfe des Index zu optimieren, um eine Sortieroperation zu vermeiden. Einschließlich der score
-Spalte im Index ermöglicht es, die Abfrage vollständig aus dem Index zu befriedigen, ohne die vom Index referenzierten Datenseiten besuchen (nachschlagen) zu müssen.
Das ist die schnelle Antwort. Die längere Antwort lautet, dass MySQL höchstwahrscheinlich keinen Index mit der führenden Spalte happened_id
verwendet für die Ansichtsabfrage.
Warum die Ansicht ein Leistungsproblem verursacht
Eines der Probleme, die Sie mit der MySQL-Ansicht haben, ist, dass MySQL das Prädikat nicht von der äußeren Abfrage nach unten in die Ansichtsabfrage "schiebt".
Ihre äußere Abfrage gibt WHERE happened_in = 2006
an . Der MySQL-Optimierer berücksichtigt das Prädikat nicht, wenn er die innere "Ansichtsabfrage" ausführt. Diese Abfrage für die Ansicht wird separat vor der äußeren Abfrage ausgeführt. Die Ergebnismenge aus der Ausführung dieser Abfrage wird "materialisiert"; Das heißt, die Ergebnisse werden als Zwischentabelle MyISAM gespeichert. (MySQL nennt es eine „abgeleitete Tabelle“, und dieser Name, den sie verwenden, ist sinnvoll, wenn Sie die Operationen verstehen, die MysQL durchführt.)
Die Quintessenz ist, dass der Index, den Sie auf happened_in
definiert haben wird von MySQL nicht verwendet, wenn es die Abfrage ausführt, die die Ansichtsdefinition bildet.
Nachdem die „abgeleitete Zwischentabelle“ erstellt wurde, wird DANN die äußere Abfrage ausgeführt, wobei diese „abgeleitete Tabelle“ als Rowsource verwendet wird. Wenn diese äußere Abfrage ausgeführt wird, ist happened_in = 2006
Prädikat wird ausgewertet.
Beachten Sie, dass alle Zeilen aus der Ansichtsabfrage gespeichert werden, was (in Ihrem Fall) eine Zeile für JEDEN Wert von happened_in
ist , nicht nur die, für die Sie in der äußeren Abfrage ein Gleichheitsprädikat angeben.
Die Art und Weise, wie Ansichtsabfragen verarbeitet werden, kann von einigen "unerwartet" sein, und dies ist einer der Gründe, warum die Verwendung von "Ansichten" in MySQL im Vergleich zu der Art und Weise, wie Ansichtsabfragen von anderen relationalen Datenbanken verarbeitet werden, zu Leistungsproblemen führen kann.
Verbesserung der Performance der Ansichtsabfrage mit einem geeigneten abdeckenden Index
Angesichts Ihrer Ansichtsdefinition und Ihrer Abfrage erhalten Sie am besten eine Zugriffsmethode "Using index" für die Ansichtsabfrage. Dazu benötigen Sie einen übergeordneten Index, z. B.
... ON highscores (player, happened_in, score).
Dies ist wahrscheinlich der vorteilhafteste Index (in Bezug auf die Leistung) für Ihre vorhandene Ansichtsdefinition und Ihre vorhandene Abfrage. Der player
Spalte ist die führende Spalte, da Sie in der Ansichtsabfrage ein Gleichheitsprädikat für diese Spalte haben. Der happened_in
Als nächstes kommt die Spalte, weil Sie eine GROUP BY-Operation für diese Spalte haben und MySQL in der Lage sein wird, diesen Index zu verwenden, um die GROUP BY-Operation zu optimieren. Wir fügen auch die score
hinzu -Spalte, da dies die einzige andere Spalte ist, auf die in Ihrer Abfrage verwiesen wird. Das macht den Index zu einem „überdeckenden“ Index, da MySQL diese Abfrage direkt von den Indexseiten aus beantworten kann, ohne Seiten in der zugrunde liegenden Tabelle besuchen zu müssen. Und das ist so gut wie wir aus diesem Abfrageplan herauskommen werden:"Using index" ohne "Using filesort".
Vergleichen Sie die Leistung mit einer eigenständigen Abfrage ohne abgeleitete Tabelle
Sie können den Ausführungsplan für Ihre Abfrage mit der Ansicht und einer entsprechenden eigenständigen Abfrage vergleichen:
SELECT player
, MAX(score) AS highest_score
, happened_in
FROM highscores
WHERE player = 24
AND happened_in = 2006
GROUP
BY player
, happened_in
Die eigenständige Abfrage kann auch einen abdeckenden Index verwenden, z.
... ON highscores (player, happened_in, score)
aber ohne die Notwendigkeit, eine MyISAM-Zwischentabelle zu materialisieren.
Ich bin mir nicht sicher, ob einer der vorherigen eine direkte Antwort auf die von Ihnen gestellte Frage liefert.
F:Wie bringe ich MySQL dazu, einen INDEX für Ansichtsabfragen zu verwenden?
A:Definieren Sie einen geeigneten INDEX, den die Ansichtsabfrage verwenden kann.
Die kurze Antwort lautet:Stellen Sie einen „deckenden Index“ bereit (der Index enthält alle Spalten, auf die in der Ansichtsabfrage verwiesen wird). Die führenden Spalten in diesem Index sollten die Spalten sein, auf die mit Gleichheitsprädikaten verwiesen wird (in Ihrem Fall die Spalte player
wäre eine führende Spalte, weil Sie einen player = 24
haben Prädikat in der Abfrage. Außerdem sollten die Spalten, auf die in GROUP BY verwiesen wird, führende Spalten im Index sein, was es MySQL ermöglicht, GROUP BY
zu optimieren -Operation, indem der Index verwendet wird, anstatt eine Sortieroperation zu verwenden.
Der entscheidende Punkt hier ist, dass die Ansichtsabfrage im Grunde eine eigenständige Abfrage ist; die Ergebnisse dieser Abfrage werden in einer "abgeleiteten" Zwischentabelle gespeichert (eine MyISAM-Tabelle, die erstellt wird, wenn eine Abfrage für die Ansicht ausgeführt wird.
Die Verwendung von Ansichten in MySQL ist nicht unbedingt eine "schlechte Idee", aber ich möchte diejenigen, die sich für die Verwendung von Ansichten in MySQL entscheiden, dringend davor warnen, sich bewusst zu sein, wie MySQL Abfragen verarbeitet, die auf diese Ansichten verweisen. Und die Art und Weise, wie MySQL Ansichtsabfragen verarbeitet, unterscheidet sich (erheblich) von der Art und Weise, wie Ansichtsabfragen von anderen Datenbanken (z. B. Oracle, SQL Server) behandelt werden.