Warum ist MySQL bei der Verwendung von LIMIT in meiner Abfrage langsam?

8

Ich versuche herauszufinden, warum eine meiner Fragen langsam ist und wie ich es beheben kann, aber ich bin ein wenig verwirrt über meine Ergebnisse.

Ich habe eine orders -Tabelle mit ungefähr 80 Spalten und 775179 Zeilen und mache folgende Anfrage:

SELECT * FROM orders WHERE id_state = 2 AND id_mp IS NOT NULL ORDER BY creation_date DESC LIMIT 200

gibt 38 Zeilen in 4.5s zurück

Beim Entfernen von ORDER BY bekomme ich eine schöne Verbesserung:

SELECT * FROM orders WHERE id_state = 2 AND id_mp IS NOT NULL LIMIT 200

38 Zeilen in 0.30s

Aber wenn ich die LIMIT entferne, ohne die ORDER BY zu berühren, bekomme ich ein noch besseres Ergebnis:

SELECT * FROM orders WHERE id_state = 2 AND id_mp IS NOT NULL ORDER BY creation_date DESC

38 Zeilen in 0.10s (??)

Warum ist mein LIMIT so hungrig?

WEITER WEITER

Ich habe ein paar Dinge versucht, bevor ich meine Antwort gesendet habe und nachdem ich bemerkt habe, dass ich einen Index für creation_date hatte (was ein datetime ist), entfernte ich ihn und die erste Abfrage läuft nun in 0.10s. Warum ist das so?

BEARBEITEN

Gut geraten, ich habe Indizes auf den anderen Spalten Teil der wo.

%Vor%

1 Reihe im Satz (0.00 sec)

%Vor%     
Alexandre Jacob 19.07.2013, 13:53
quelle

2 Antworten

6

Indizes verbessern nicht notwendigerweise die Leistung. Um besser zu verstehen, was passiert, wäre es hilfreich, wenn Sie die explain für die verschiedenen Abfragen eingefügt hätten.

Meine beste Schätzung wäre, dass Sie einen Index in id_state oder sogar id_state, id_mp haben, der verwendet werden kann, um die where -Klausel zu erfüllen. Wenn ja, würde die erste Abfrage ohne order by diesen Index verwenden. Es sollte ziemlich schnell sein. Dies erfordert auch ohne Index einen sequentiellen Scan der Seiten in der Tabelle orders , der immer noch ziemlich schnell sein kann.

Wenn Sie dann den Index für creation_date hinzufügen, entscheidet sich MySQL, diesen Index stattdessen für order by zu verwenden. Dies erfordert das Lesen jeder Zeile im Index, dann das Abrufen der entsprechenden Datenseite, um die where -Bedingungen zu prüfen und die Spalten zurückzugeben (falls es eine Übereinstimmung gibt). Dieses Lesen ist sehr ineffizient, da es nicht in der "Seiten" -Reihenfolge ist, sondern vielmehr durch den Index spezifiziert wird. Zufällige Lesevorgänge können ziemlich ineffizient sein.

Schlimmer noch, obwohl Sie eine limit haben, müssen Sie immer noch die gesamte Tabelle lesen, da die gesamte Ergebnismenge benötigt wird. Obwohl Sie eine Sortierung für 38 Datensätze gespeichert haben, haben Sie eine massiv ineffiziente Abfrage erstellt.

Diese Situation wird übrigens deutlich schlechter, wenn die Tabelle orders nicht in den verfügbaren Speicher passt. Dann haben Sie eine Bedingung namens "Thrashing", bei der jeder neue Datensatz dazu neigt, einen neuen I / O-Read zu generieren. Wenn also eine Seite 100 Datensätze enthält, muss die Seite möglicherweise 100 Mal gelesen werden.

Sie können alle diese Abfragen schneller ausführen, indem Sie einen Index für orders(id_state, id_mp, creation_date) erstellen. Die where -Klausel verwendet die ersten beiden Spalten und die order by die letzte.

    
Gordon Linoff 19.07.2013, 14:16
quelle
0

Dasselbe Problem ist in meinem Projekt passiert, Ich habe einen Test gemacht und herausgefunden, dass LIMIT wegen Zeilenaufrufe langsam ist

Siehe: MySQL ORDER BY / LIMIT Leistung: Late-Row-Lookups

Also, die Lösung ist:

(A) Wenn Sie LIMIT verwenden, wählen Sie nicht alle Spalten aus, sondern nur die PK-Spalten

(B) Markieren Sie alle benötigten Spalten und verbinden Sie sie mit der Ergebnismenge von (A)

SQL sollte gerne:

%Vor%

in meiner Datenbank,

Das alte SQL, das alle Spalten mit "LIMIT 21560, 20" auswählt, kostet ungefähr 4.484s.

Der neue Sql kostet nur 0,063s. Der neue ist etwa 71 mal schneller

    
Li Ying 02.12.2016 08:14
quelle

Tags und Links