2017-11-21 2 views
2

Erzielen eines seltsamen Verhaltens von MySQL 5.6. Die folgende Abfrage soll einige einfache Daten aus einem Join auswählen. Was gut funktioniert.Doppelte Spalte in Select-Abfrage führt zu schnellerer Abfrageausführung

SELECT 
    f.followID, 
    l.object_id, 
    l.created_at, 
    ROUND(UNIX_TIMESTAMP(l.created_at)/(3600)) window 
FROM fb_follow f LEFT JOIN fb_likes l ON f.followID = l.user_id 
WHERE f.profileID = 1 
    AND l.created_at > '20171119' LIMIT 1000; 

Das Merkwürdige passiert, wenn ich versehentlich ein Duplikat der Linie l.created_at enthalten.

SELECT 
    f.followID, 
    l.object_id, 
    l.created_at, 
    l.created_at, 
    ROUND(UNIX_TIMESTAMP(l.created_at)/(3600)) window 
FROM fb_follow f LEFT JOIN fb_likes l ON f.followID = l.user_id 
WHERE f.profileID = 1 
    AND l.created_at > '20171119' LIMIT 1000; 

Die Abfrageausführungszeit ging von ~ 600 ms bis ~ 350 ms (für verschiedene Werte von f.profileID wiederholt. Was ist der Grund für niedrigere Abfragezeit sein kann? Meine Erwartung ist, dass sie zumindest weniger Zeit, da weniger Daten übernehmen würden zurück?

+1

War dieser Lauf unmittelbar nach dem ersten? Der Grund ist, wenn die fraglichen Daten noch im Speicher sind, könnte es allein dafür schneller laufen. Oder hast du das in wiederholten (gefahrenen) Läufen zwischen beiden gesehen? – kchason

+0

Ja wiederholt läuft auf beiden Beispielen mit dem gleichen Ergebnis. – capitrane

+0

Cache wie in InnoDB Pufferpool (Speicher) und Festplatten-Cache sind wahrscheinlich zu niedrigeren Ausführungszeit –

Antwort

1

Zwei Caches

Ändern SELECT-SELECT SQL_NO_CACHE die Verwendung der "Query Cache" eliminiert.

Wenn der Abfragecache verwendet wird, beträgt die Abfragezeit in der Regel 1 ms oder weniger. 350ms sagen, dass es nicht die QC war.

Der andere Hauptcache ist InnoDBs buffer_pool. (Sie sind mit InnoDB, richtig?) Wenn Sie zuerst eine Abfrage ausführen, kann müssen die Festplatte zu schlagen, um den Index und/oder Datenblöcke zu erhalten. Das zweite Mal, diese Blöcke können noch im Pufferpool (im RAM) zwischengespeichert werden, daher wird die Abfrage schneller sein.

Der Unterschied ist oft ein Faktor von 10. Aber es gibt viele Ausnahmen. 600 vs 350 passt nicht zum Muster, aber das ist nicht schlüssig.

Also, wenn Timing zwei Dinge tun:

  1. SELECT SQL_NO_CACHE ...
  2. Führen Sie die Abfrage zweimal, und das zweite Timing verwenden.

ERKLÄREN

Bitte führen Sie EXPLAIN SELECT ... für jede Variation. Wenn es einen Unterschied gibt (was ich bezweifle), könnte dies neue Erkenntnisse darüber liefern, warum "das Duplizieren einer Linie das Timing verändert hat".

JOIN

nicht LEFT Verwenden Sie, wenn Sie es nicht brauchen. Es verwirrt den Leser. Da Sie explizit auf f.profileID = 1 filtern, wird LEFT ignoriert (und kann entfernt werden).

ORDER BY

ein LIMIT ohne ORDER BY zu haben, ist in der Regel Torheit. Welche 1000 Zeilen willst du? Das Hinzufügen eines ORDER BY würde die Entscheidung explizit machen. Ja, es kann die Abfrage verlangsamen.

nützlicher Indizes

Für eine bessere Leistung:

`f` needs INDEX(followID, profileID) -- in this order 
`u` needs INDEX(created_at) 
+0

(EXPLAIN) Beide geben die gleiche Erklärung zurück. (INDEXING) Ich erkenne jetzt, dass in der Datenbank, die ich dachte, dass vorhanden war Index fehlt. In Bezug auf "LIMIT" ohne "ORDER BY" ist der Anwendungsfall eher ein Muster, so dass die Reihenfolge nicht so wichtig ist (aber guter Punkt). – capitrane

+0

Ja, "Sampling" ist ein gültiger Grund für das Überspringen der 'ORDER BY'. (Bei den meisten Fragen in diesem Forum geht es jedoch um Produktionsabfragen; daher bin ich zu einer falschen Schlussfolgerung gelangt.) –

Verwandte Themen