it-swarm.com.de

Warum verlangsamt MYSQL mit einem höheren LIMIT-Offset die Abfrage?

Kurzes Szenario: Eine Tabelle mit mehr als 16 Millionen Datensätzen [2 GB groß]. Je höher der LIMIT-Offset bei SELECT, desto langsamer wird die Abfrage, wenn ORDER BY * primary_key * verwendet wird.

So

SELECT * FROM large ORDER BY `id`  LIMIT 0, 30 

dauert weit weniger als

SELECT * FROM large ORDER BY `id` LIMIT 10000, 30 

Das bestellt nur 30 Platten und so weiter. Es ist also nicht der Overhead von ORDER BY.
Jetzt dauert das Abrufen der letzten 30 Zeilen ca. 180 Sekunden. Wie kann ich diese einfache Abfrage optimieren?

151
Rahman

Es ist normal, dass höhere Offsets die Abfrage verlangsamen, da die Abfrage die ersten OFFSET + LIMIT - Datensätze abzählen muss (und nur LIMIT von ihnen nimmt). Je höher dieser Wert ist, desto länger dauert die Abfrage.

Die Abfrage kann nicht direkt an OFFSET gesendet werden, da zum einen die Datensätze unterschiedlich lang sein können und zum anderen Lücken aus gelöschten Datensätzen bestehen können. Es muss jeden Datensatz auf seinem Weg überprüfen und zählen.

Angenommen, id ist ein PRIMARY KEY Einer MyISAM Tabelle, können Sie dies mit folgendem Trick beschleunigen:

SELECT  t.*
FROM    (
        SELECT  id
        FROM    mytable
        ORDER BY
                id
        LIMIT 10000, 30
        ) q
JOIN    mytable t
ON      t.id = q.id

Siehe diesen Artikel:

174
Quassnoi

Ich hatte genau das gleiche Problem. Angesichts der Tatsache, dass Sie eine große Menge dieser Daten und nicht einen bestimmten Satz von 30 erfassen möchten, werden Sie wahrscheinlich eine Schleife ausführen und den Versatz um 30 erhöhen.

Was Sie stattdessen tun können, ist:

  1. Halten Sie die letzte ID eines Datensatzes (30) (z. B. lastId = 530)
  2. Bedingung hinzufügen WHERE id > lastId limit 0,30

Sie können also immer einen NULL-Offset haben. Sie werden von der Leistungssteigerung begeistert sein.

190
Nikos Kyr

MySQL kann nicht direkt zum 10000. Datensatz (oder zum 80000. Byte, wie Sie vorschlagen) wechseln, da es nicht davon ausgehen kann, dass er so gepackt/geordnet ist (oder kontinuierliche Werte zwischen 1 und 10000 aufweist). Obwohl es in Wirklichkeit so sein könnte, kann MySQL nicht davon ausgehen, dass es keine Lücken/Lücken/gelöschten IDs gibt.

Wie bereits erwähnt, muss MySQL 10000 Zeilen abrufen (oder 10000. Einträge des Index auf id durchlaufen), bevor die 30 gefunden werden, die zurückgegeben werden sollen.

EDIT : Um meinen Standpunkt zu veranschaulichen

Beachten Sie, dass obwohl

SELECT * FROM large ORDER BY id LIMIT 10000, 30 

wäre langsam (er) ,

SELECT * FROM large WHERE id >  10000 ORDER BY id LIMIT 30 

wäre schnell (er) und würde dieselben Ergebnisse zurückgeben, vorausgesetzt, es fehlen keine ids (d. h. Lücken).

17
Riedsio

Ich habe ein interessantes Beispiel gefunden, um SELECT-Abfragen zu optimieren ORDER BY id LIMIT X, Y. Ich habe 35 Millionen Zeilen, so dass es ungefähr 2 Minuten gedauert hat, eine Reihe von Zeilen zu finden.

Hier ist der Trick:

select id, name, address, phone
FROM customers
WHERE id > 990
ORDER BY id LIMIT 1000;

Setzen Sie einfach das WHERE mit der letzten ID ein, um die Leistung zu steigern. Für mich war es von 2 Minuten bis 1 Sekunde :)

Weitere interessante Tricks hier: http://www.iheavy.com/2013/06/19/3-ways-to-optimize-for-paging-in-mysql/

Das funktioniert auch mit Streichern

7
sym

Der zeitaufwändige Teil der beiden Abfragen besteht darin, die Zeilen aus der Tabelle abzurufen. Logischerweise in der LIMIT 0, 30 Version, nur 30 Zeilen müssen abgerufen werden. In dem LIMIT 10000, 30 Version werden 10000 Zeilen ausgewertet und 30 Zeilen zurückgegeben. Während des Datenlesevorgangs kann eine gewisse Optimierung vorgenommen werden. Beachten Sie jedoch Folgendes:

Was wäre, wenn Sie eine WHERE-Klausel in den Abfragen hätten? Die Engine muss alle qualifizierten Zeilen zurückgeben, dann die Daten sortieren und schließlich die 30 Zeilen abrufen.

Berücksichtigen Sie auch den Fall, in dem Zeilen in der ORDER BY-Sequenz nicht verarbeitet werden. Alle qualifizierenden Zeilen müssen sortiert werden, um zu bestimmen, welche Zeilen zurückgegeben werden sollen.

5
bobs