2017-12-20 5 views
0

Ich habe gerade eine Tabelle mit:MySQL hat verwenden Index in SUM nicht mit GROUP BY-Abfrage

CREATE TABLE `table_test` (
`time` date NOT NULL, 
`line_id` char(36) NOT NULL, 
`location_id` char(36) NOT NULL, 
`placement_id` char(36) NOT NULL, 
`flight_id` char(36) NOT NULL, 
`impressions` int(11) DEFAULT `0`, 
PRIMARY KEY (`time`,`line_id`,`location_id`,`placement_id`,`flight_id`), 
KEY `table_test_IDX` (`time`,`placement_id`,`line_id`,`impressions`) USING 
BTREE 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 

Dann, wenn ich versuche, eine Abfrage auszuführen:

SELECT 
    time, 
    placement_id, 
    line_id, 
    SUM(impressions) AS totalImpress 
FROM 
    table_test 
WHERE 
    time BETWEEN '2017-11-01' AND '2017-11-30' 
GROUP BY time , placement_id , line_id; 

Es ist immer Using where; Using temporary; Using filesort verwendet, in In diesem Fall möchte ich, dass die Abfrage table_test_IDX verwendet.

Was habe ich hier falsch gemacht?

Vielen Dank.

Antwort

0

Wenn Sie die MySQL documentation für die Optimierung der Aggregation Abfragen durchlesen, werden Sie feststellen, dass es zwei Methoden gibt, eine GROUP BY Abfrage zu optimieren, nämlich lose und enge Index-Scans. Eine Einschränkung für diese beiden Scans besteht jedoch darin, dass die einzigen in der Auswahlliste verwendeten Aggregatfunktionen MIN oder MAX sind. Da Sie eine SUM auswählen, sind diese Optimierungen nicht verfügbar.

Es ist sinnvoll, einen Index zu verwenden, von dem Ihre WHERE-Klausel profitieren kann, da dies dazu führen kann, dass Datensätze frühzeitig aus dem Ergebnissatz im Abfrageplan gelöscht werden. Um jedoch eine Summe für jede Gruppe zu berechnen, muss MySQL jeden Datensatz in der verbleibenden Tabelle berühren. Es gibt keinen Weg um eine Summe zu bekommen, also ist es egal wie wir auf alle diese Datensätze zugreifen.

+0

Danke Tim für Ihre Antwort. Aber ich frage mich, wenn ich versuche, die Abfrage mit dieser Option auszuführen: 'USE INDEX (table_test_IDX)'. Die Abfragezeit ist 2x schneller als normal. –

+0

Ja, aber an welcher Stelle in der Abfrage wird der Index verwendet? Der Optimierer bringt die Dinge nicht immer in Ordnung. Wenn Sie einen relativ kleinen Datensatz mit vernünftigen Laufzeiten haben, würde ich nicht über Dinge analysieren; die meiste Zeit ist der Optimierer schlauer als Sie. –

0

Ich nehme an, dass Sie UUIDs verwenden? Ändern Sie CHAR(36) zu CHAR(36) CHARACTER SET ascii. Besser wäre es, sie in `BINARY (16) zu packen. (Siehe http://mysql.rjweb.org/doc.php/uuid.) Dies verkleinert die Größe von 108 auf 36 bis 16.

Sie sagen, dass es filesort usw. verwendet, aber verwendet es PRIMARY? Bitte geben Sie die EXPLAIN SELECT ... an.

Um jedoch noch mehr Geschwindigkeit zu erreichen, sollten Sie "Übersichtstabelle (n)" erstellen und warten. (Siehe http://mysql.rjweb.org/doc.php/summarytables.) Wenn Sie pro Kombination von (time, plazier_id, line_id) eine Zeile in einer Übersichtstabelle hätten, könnten GROUP BY und entfernt werden. (Wenn Sie nach Stunden zusammenfassen, würden Sie diese immer noch benötigen.)