優化LIMIT分頁
在系統中需要進行分頁才做的時候,我們通常會使用LIMIT加上偏移量的辦法實現。
比如:
explain select * from orders limit 10 offset 10 ;
一個非常常見又令人頭疼的問題就是,在偏移量非常大的時候(翻頁到非常靠后的頁面),例如可能是LIMIT 10000,10這樣的查詢,這時MySQL需要查詢10020條記錄然后只返回最后20條,前面10000條記錄都被拋棄,這樣的代價非常高。
那么如何優化這類查詢呢?
第一步
首先對于這個查詢select id from orders;
我們可以explain
一下
explain select id from orders;
會發現這是一個索引掃描(在存在輔助索引的情況下),相對表掃描這
個是會快很多的
第二步
基與上面的理論那么先將需要的id取出來 然后做一個子查詢
select * from orders WHERE id >= (select id from orders order by id limit 1 offset 10000) limit 10;
不過這個查詢是基于ID自增的假設,如果ID不是自增, 那么可以通過INNER JOIN
來改寫
select * from orders INNER JOIN (select id from orders order by id LIMIT 10 offset 10000) t USING (id);
補充
-
分頁的顯示
- 如果有獲取數據總數 那么通過總數自然可以得到頁數
一般獲取數據總數是一個索引掃描,如果數據量很大在innodb下對于sql什么優化的有段 - 如果沒有總數 那么獲取的時候多獲取一些數據, 比如每頁20個 我獲取21個 如果能取到自然有下一頁
- 如果有獲取數據總數 那么通過總數自然可以得到頁數
-
還是很慢怎么解決
- 從業務考慮 是否真的需要這種翻頁, 因為普通用戶的話很少會關心歷史數據
- 可以考慮按時間段分表
- 維護一根分頁表,這樣直接就可以獲得某也有多少數據
- 交給其他工具去做,不讓mysql做自己不擅長的事情
總結
優化此類分頁查詢的一個最簡單的辦法就是盡可能地使用索引覆蓋查詢,而不是查詢所有的列。然后根據需要做一個關聯操作再返回所需的列。對于偏移量很大的時候,這樣做的效率會提升很大。