2016-08-30 5 views
2

I 29.900.000 Datensätze in der Tabelle haben, Offsetaufwendig zu viel Abfrageausführungszeitmysql InnoDB wählen langsame Offset

SELECT * FROM table_records LIMIT 50 OFFSET 1999950 
this query taking 33.087 sec 

Ich habe mich verändert Offset als 2000000

SELECT * FROM table_records LIMIT 50 OFFSET 2000000 
this query taking 2.030 sec 

explaination

EXPLAIN SELECT * FROM table_records LIMIT 50 OFFSET 29941250 


id | select_type | table   | type | possible_keys | key  | key_len | ref |rows  | Extra 
1 | SIMPLE  | table_records | index | (NULL)  | PRIMARY | 4  | (NULL) |29900771 |   

Ich habe Offset nur als Grenzwert

entfernt entfernt
SELECT * FROM table_records LIMIT 50 
this query taking 0.002 sec 

Jeder Vorschlag oder Idee geschätzt.

+1

Höher der Offset langsamer die Abfrage. Related [** post **] (http://stackoverflow.com/questions/4481388/why-does-mysql-higher-limit-offset-slow-the-query-down) – 1000111

+0

Versuchen Sie, die Verwendung von Offset – Mike

+0

zu vermeiden Ist dieser Bug oder diese Einschränkung, benutze ich ihn um die Paginierung der Seite aufzulisten. :(jede andere Lösung? – user3151197

Antwort

1

Es gibt eine Lösung, es schneller zu tun, aber es funktioniert nur, wenn Sie einen Primärschlüssel Int und keine Lücken in dieser Tabelle haben. Ich meine, Sie erlauben keine Löschung. In diesem Fall wird Ihre Abfrage wie folgt aussehen:

SELECT * FROM table_records where id >= 1999950 order by id LIMIT 50; 
+0

es wird nach dem Löschen einiger Datensätze fehlgeschlagen, aber ich fand Lösung von [Quassnois Antwort] (http://stackoverflow.com/questions/4481388/why-does-mysql-higher-limit-offset-slow-the-query-down) – user3151197

2

Es geht nur um Caching.

Einfach gesagt, OFFSET saugt. Es muss alle "Offset" -Reihen lesen und ignorieren und dann "Limit" -Reihen liefern.

Wenn die Zeilen übersprungen werden, müssen sie die Zeilen holen - wenn sie auf der Festplatte sind, braucht es Zeit; Wenn sie im RAM zwischengespeichert werden, ist es viel schneller. (Oft 10-mal so schnell.)

Was wahrscheinlich passiert in Ihrem Fall: Die erste Abfrage gefunden wenige, wenn überhaupt, der Zeilen im RAM, so dass es die meisten oder alle 1999950 Zeilen hatte.

Dann hat Ihre zweite Abfrage die 1999950 Zeilen schnell gescannt und dann die letzten 50 von der Festplatte abgerufen. (. Oder vielleicht die letzten 50 bereits hereinkam, da die Einheit von I/O ist ein „Block“ von Datensatz)

Mit LIMIT und/oder OFFSET, gibt EXPLAIN selten irgendwelche Hinweise - es gibt in der Regel eine Schätzung der Gesamtzahl der Zeilen in der Tabelle.

Es gibt noch ein anderes Problem mit Ihren Beispielen ... Sie haben keine ORDER BY. So kann der Motor beliebige Reihen liefern. Normalerweise ist es vorhersehbar, aber manchmal kann es Überraschungen geben.

Aber, sobald Sie ein ORDER BY hinzufügen, es kann Bedarf eine temporäre Tabelle und sortieren noch bevor immer den ersten Datensatz zu sein! Das heißt, SELECT ... ORDER BY .. LIMIT 50kann so langsam sein wie alle anderen - wenn Sie etwas Unangenehmes für die Indizes usw. bestellen, die beteiligt sind.

Siehe how OFFSET sucks when paginating web pages. Das beinhaltet eine Problemumgehung durch "Erinnern, wo Sie aufgehört haben". Und this zeigt, wie man die nächsten 1000 Zeilen effizient erhält, sogar mit Lücken in IDs.