Kurzes Szenario: Eine Tabelle mit mehr als 16 Millionen Datensätzen [2 GB groß]. Je höher der LIMIT-Offset mit SELECT ist, 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 oder so. Es ist also nicht der Overhead von ORDER BY.
Beim Abrufen der letzten 30 Zeilen dauert es ungefähr 180 Sekunden. Wie kann ich diese einfache Abfrage optimieren?
mysql
performance
sql-order-by
limit
Rahman
quelle
quelle
Antworten:
Es ist normal, dass höhere Offsets die Abfrage verlangsamen, da die Abfrage die ersten
OFFSET + LIMIT
Datensätze abzählen muss (und nurLIMIT
diese nimmt). Je höher dieser Wert ist, desto länger läuft die Abfrage.Die Abfrage kann nicht direkt ausgeführt werden,
OFFSET
da erstens die Datensätze unterschiedlich lang sein können und zweitens Lücken zu gelöschten Datensätzen bestehen können. Es muss jeden Datensatz auf seinem Weg überprüfen und zählen.Angenommen, es
id
handelt sichPRIMARY KEY
um eineMyISAM
Tabelle, können Sie sie mit diesem Trick beschleunigen:Siehe diesen Artikel:
quelle
ORDER BY
oder der Index alle benötigten Felder abdeckt, benötigen Sie diese Problemumgehung nicht.postgresql
. Dies ist eine MySQL-spezifische Antwort.Ich hatte selbst 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, führen Sie wahrscheinlich eine Schleife aus und erhöhen den Versatz um 30.
Was Sie stattdessen tun können, ist:
WHERE id > lastId limit 0,30
Sie können also immer einen NULL-Offset haben. Sie werden von der Leistungsverbesserung begeistert sein.
quelle
MySQL kann nicht direkt zum 10000. Datensatz (oder zum 80000. Byte als Vorschlag) wechseln, da nicht davon ausgegangen werden kann, dass es so gepackt / geordnet ist (oder dass es kontinuierliche Werte in 1 bis 10000 hat). Obwohl dies in Wirklichkeit so sein könnte, kann MySQL nicht davon ausgehen, dass es keine Lücken / Lücken / gelöschten IDs gibt.
Wie Bob bemerkt hat, muss MySQL also 10000 Zeilen abrufen (oder 10000. Einträge des Index durchlaufen
id
), bevor die 30 gefunden werden, die zurückgegeben werden sollen.EDIT : Um meinen Standpunkt zu veranschaulichen
Beachten Sie, dass obwohl
wäre langsam (äh) ,
wäre schnell (er) und würde die gleichen Ergebnisse zurückgeben, vorausgesetzt, es fehlen keine
id
s (dh Lücken).quelle
Ich habe ein interessantes Beispiel gefunden, um SELECT-Abfragen zu optimieren. ORDER BY id LIMIT X, Y. Ich habe 35 Millionen Zeilen, also dauerte es ungefähr 2 Minuten, um eine Reihe von Zeilen zu finden.
Hier ist der Trick:
Setzen Sie einfach das WO mit der letzten ID, die Sie erhalten haben, um die Leistung erheblich 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/
Es funktioniert auch mit Strings
quelle
Der zeitaufwändige Teil der beiden Abfragen besteht darin, die Zeilen aus der Tabelle abzurufen. Logischerweise müssen in der
LIMIT 0, 30
Version nur 30 Zeilen abgerufen werden. In derLIMIT 10000, 30
Version werden 10000 Zeilen ausgewertet und 30 Zeilen zurückgegeben. Während des Datenlesevorgangs kann eine Optimierung durchgeführt 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, die Daten sortieren und schließlich die 30 Zeilen abrufen.
Betrachten Sie auch den Fall, in dem Zeilen nicht in der ORDER BY-Sequenz verarbeitet werden. Alle qualifizierenden Zeilen müssen sortiert werden, um zu bestimmen, welche Zeilen zurückgegeben werden sollen.
quelle
Für diejenigen, die an einem Vergleich und Zahlen interessiert sind :)
Experiment 1: Der Datensatz enthält ungefähr 100 Millionen Zeilen. Jede Zeile enthält mehrere BIGINT-, TINYINT- und zwei TEXT-Felder (absichtlich) mit etwa 1k Zeichen.
SELECT * FROM post ORDER BY id LIMIT {offset}, 5
SELECT t.* FROM (SELECT id FROM post ORDER BY id LIMIT {offset}, 5) AS q JOIN post t ON t.id = q.id
... WHERE id>xxx LIMIT 0,5
hier nicht, da es sich um eine konstante Zeit handeln sollte.Experiment 2: Ähnliches, außer dass eine Reihe nur 3 BIGINTs hat.
quelle