2016-08-30 25 views
2

我有2990萬點的記錄表,抵消消耗太多的查詢執行時間MySQL的InnoDB的選擇刀慢

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

我已經改變了偏移量200萬

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

交代

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 |   

我已經刪除偏移量只是設置爲限制

SELECT * FROM table_records LIMIT 50 
this query taking 0.002 sec 

任何建議或想法讚賞。

+1

查詢的偏移越慢。相關[**帖子**](http://stackoverflow.com/questions/4481388/why-does-mysql-higher-limit-offset-slow-the-query-down) – 1000111

+0

儘量避免使用偏移量 – Mike

+0

是這個錯誤還是限制,我用它來列表頁面的分頁。 :(任何其他解決方案? – user3151197

回答

1

有一種解決方案可以更快地完成它,但只有在此表中有主鍵int且沒有間隙時才能工作。我的意思是你不允許刪除。在這種情況下,您的查詢將如下所示:

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

刪除一些記錄後,它會失敗,但我發現[Quassnoi的答案]解決方案(http://stackoverflow.com/questions/4481388/why-does-mysql-higher-limit-offset-slow-the-query-down) – user3151197

2

這完全是關於緩存。

簡單地說,OFFSET很爛。它必須讀取並忽略所有「偏移」行,然後傳遞「限制」行。

跳過行時,它必須獲取行 - 如果它們在磁盤上,則需要時間;如果它們被緩存在RAM中,速度會更快。 (通常10倍的速度。)

什麼可能你的情況發生了:第一個查詢發現很少,如果有的話,在RAM行的,所以也只好大部分或全部的1999950行。

然後您的第二個查詢快速掃描了1999950行,然後從磁盤中獲取最後的50個。 (或者可能是在過去的50排在已,因爲I/O的單位是一個記錄「塊」)

隨着LIMIT和/或OFFSETEXPLAIN很少給任何線索 - 它通常提供了一個估計表中總行數的

您的示例還有另一個問題...您沒有ORDER BY。所以,引擎可以隨意交付任何喜歡的行。通常情況下它是可預測的,但有時你可以得到驚喜。

但是,一旦你添加一個ORDER BY,有可能需要是一個臨時表並獲得第一條記錄排序甚至在!也就是說,SELECT ... ORDER BY .. LIMIT 50可能與所有其他人一樣慢 - 如果您正在通過不方便的索引等方式進行排序,則會涉及到這些問題。

參見how OFFSET sucks when paginating web pages。這包括通過「記住你離開的地方」的解決方法。 this顯示瞭如何有效地獲取下一個1000行,即使在ID中存在空白。