2012-11-29 8 views
28

Ich arbeite an einem Event-Tracking-System, das eine Handvoll Lookup-Tabellen sowie die primäre Logging-Tabelle verwendet. In einem Bericht, den ich schreibe, kann ein Objekt ausgewählt werden, um Statistiken anzuzeigen. Die Oberfläche zeigt alle Objekte in der Reihenfolge abnehmender Wichtigkeit (dh Treffer) an.Index verwenden, temporäre verwenden, mit filesort - wie das zu beheben?

Das Schema für die beiden Tabellen (leicht abgespeckte, aber Sie erhalten den Kern):

CREATE TABLE IF NOT EXISTS `event_log` (
    `event_id` int(11) NOT NULL AUTO_INCREMENT, 
    `user_id` int(5) DEFAULT NULL, 
    `object_id` int(5) DEFAULT NULL, 
    `event_date` datetime DEFAULT NULL, 
    PRIMARY KEY (`event_id`), 
    KEY `user_id` (`user_id`), 
    KEY `object_id` (`object_id`) 
); 

CREATE TABLE IF NOT EXISTS `lookup_event_objects` (
    `object_id` int(11) NOT NULL AUTO_INCREMENT, 
    `object_desc` varchar(255) NOT NULL, 
    PRIMARY KEY (`object_id`) 
); 

Die Abfrage ich Probleme mit ist unten angegeben ist, bin. Es funktioniert gut mit meiner Tabelle von ~ 100 Einträge, aber die EXPLAIN beunruhigt mich ein wenig.

explain SELECT 
      el.object_id, 
      leo.object_desc, 
      COUNT(el.object_id) as count_rows 
     FROM 
      event_log el 
      LEFT JOIN lookup_event_objects leo ON leo.object_id = el.object_id 
     GROUP BY 
      el.object_id 
     ORDER BY 
      count_rows DESC, 
      leo.object_desc ASC 

Returns: Using index; Using temporary; Using filesort

Also - was mit meinem Schema falsch ist und/oder Abfrage für MySQL zurück auf temporary und filesort zu fallen? Oder ist es so optimiert, wie es mit ORDER BY möglich ist?

Antwort

63

Nun, the doc gibt die genauen Gründe, wenn „vorübergehende Verwendung“ erscheint:

Temporäre Tabellen unter Bedingungen, wie diese erstellt werden können:

Wenn es eine ORDER BY-Klausel ist und eine andere GROUP BY-Klausel, oder wenn ORDER BY oder GROUP BY Spalten aus anderen Tabellen als der ersten Tabelle in der Join-Warteschlange enthält, wird eine temporäre Tabelle erstellt.

DISTINCT kombiniert mit ORDER BY kann eine temporäre Tabelle erfordern.

Wenn Sie die Option SQL_SMALL_RESULT verwenden, verwendet MySQL eine temporäre Tabelle im Arbeitsspeicher, es sei denn, die Abfrage enthält auch Elemente (beschrieben später), die Datenträgerspeicher erfordern.

Ein schneller Scan zeigt, dass Sie unter # 1 leiden.

Und this blog von 2009 sagt, dass "using filesort" bedeutet, dass die Sortierung nicht mit einem Index durchgeführt werden kann. Da Sie nach einem berechneten Feld sortieren, wird das auch stimmen.

Also, das ist was "falsch".

+0

Die maximale Anzahl der Objekte, die ich je von dieser Abfrage zurückgeben würde, ist <300, obwohl ich möglicherweise Millionen von Zeilen in der event_log habe. Ich habe bestätigt, dass 'using temporary' und' using filesort' weggehen, wenn ich ORDER BY entferne. Ich werde versuchen, dies zu ändern, so dass ich die Reihenfolge (in einem Array) mit der Skriptsprache (PHP) mache. Danke für Ihre Antwort und Links. –

+1

Es kann immer noch effizienter sein, die Sortierung in MySQL zu tun - es hat bereits die Daten in einer Datenstruktur geladen usw. –

+0

Es wäre sicherlich sauberer. Danke für die Rückmeldung. –

1

Dies sind die folgenden Bedingungen, unter denen temporäre Tabellen erstellt werden. UNION-Abfragen verwenden temporäre Tabellen.

Einige Ansichten erfordern temporäre Tabellen, z. B. solche, die mit dem TEMPTABLE-Algorithmus ausgewertet wurden oder die UNION oder Aggregation verwenden.

Wenn eine ORDER BY-Klausel und eine andere GROUP BY-Klausel vorhanden sind oder wenn ORDER BY oder GROUP BY Spalten aus anderen Tabellen als der ersten Tabelle in der Join-Warteschlange enthalten, wird eine temporäre Tabelle erstellt.

DISTINCT kombiniert mit ORDER BY kann eine temporäre Tabelle erfordern.

Wenn Sie die SQL_SMALL_RESULT Option verwenden, verwendet MySQL eine speicher temporäre Tabelle, es sei denn, die Abfrage auch Elemente enthält (später beschrieben), die auf Plattenspeicher benötigen.

Folgen Sie diesem Link von mysql: http://dev.mysql.com/doc/refman/5.1/en/internal-temporary-tables.html

1

Aktualisiert für MySQL 5.7 (src):

Der Server erstellt temporäre Tabellen unter Bedingungen wie diesen:

  • Bewertung der UNION-Anweisungen, mit einigen Ausnahmen später beschrieben.

  • Auswertung einiger Ansichten, z. B. derjenigen, die den TEMPTABLE-Algorithmus, UNION oder Aggregation verwenden.

  • Auswertung von abgeleiteten Tabellen (Unterabfragen in der FROM-Klausel).

  • Tabellen, die für die Unterquery- oder Semi-Join-Materialisierung erstellt wurden (siehe Abschnitt 8.2.2, "Optimierung von Unterabfragen, abgeleitete Tabellen und View-Referenzen").

  • Auswertung von Anweisungen, die eine ORDER BY-Klausel und eine andere GROUP BY-Klausel enthalten oder für die ORDER BY oder GROUP BY Spalten aus anderen Tabellen als der ersten Tabelle in der Join-Warteschlange enthalten.

  • Die Auswertung von DISTINCT kombiniert mit ORDER BY erfordert möglicherweise eine temporäre Tabelle.

  • Für Abfragen, die den Modifizierer SQL_SMALL_RESULT verwenden, verwendet MySQL eine temporäre Tabelle im Arbeitsspeicher, es sei denn, die Abfrage enthält auch Elemente (die später beschrieben werden), die Speicherplatz auf der Festplatte erfordern.

  • Um INSERT ... SELECT-Anweisungen auszuwerten, die aus derselben Tabelle auswählen und in dieselbe Tabelle einfügen, erstellt MySQL eine interne temporäre Tabelle für die Zeilen aus SELECT und fügt diese Zeilen dann in die Zieltabelle ein. Siehe Abschnitt 13.2.5.1, "INSERT ... SELECT Syntax".

  • Auswertung von UPDATE-Anweisungen für mehrere Tabellen.

  • Auswertung der Ausdrücke GROUP_CONCAT() oder COUNT (DISTINCT).

Verwandte Themen