mysql 分頁查詢使我們常見的需求 ,但是隨着頁數的增加查詢性能會逐漸下降,尤其是到深度分頁的情況。我們可以把分頁分為兩個步驟,1.定位偏移量,2.獲取分頁條數的 數據。
所以當數據較大頁數較深時就涉及一次需要耗費較長時間的操作。所以mysql深度分頁的 問題該如何解決呢 ?
首先我們來看一個簡單的查詢:
SELECT * FROM events WHERE date > '2010-01-01T00:00:00-00:00' AND event = 'editstart' ORDER BY date LIMIT 50000 50;

可以發現在一定頁數后時間延時非常明顯。結合相關文章我們的解決方式可以大致分為以下幾種.
思路:
既然分頁查詢時,定位偏移量較慢,我們可不可以減少這個偏移量的定位,使其始終曲線的前半部分,即在較少偏移量的場景。
方法一:以結果作為條件,已查詢條件的變化換取分頁的不變。
分頁查詢我們一般都是逐漸往后翻頁的,那么我們可以很清晰的知道,在當前查詢頁的最后一條數據的時間點,那么,以此時間點再查詢20條,那么 我們當前的頁數就同樣還是0,以時間點的推移換取頁數的不變,減少其偏移量的計算。
我們可以創建索引 index(date,id), id就是我們上一次的返回結果。
具體示例如下:
SELECT *FROM events WHERE (date,id) > ('2010-07-12T10:29:47-07:00',111866) AND event = 'editstart' ORDER BY date, id LIMIT 50000 50
以上方法的局限性:
1.id最好是主鍵,是否有這樣自增長的字段,或者說帶順序變化特性的列。
2.無法適應下一次分頁頁數與上一次相差較大,如由第一頁突然跳轉到50萬頁。
優點:可以適合復雜查詢條件查詢的場景。不需要改變sql語句結構
方法二:
采用子查詢模式,其原理依賴於覆蓋索引,當查詢的列,均是索引字段時,性能較快,因為其只用遍歷索引本身。我們自己創建的非主鍵索引,都是非聚集索引,其不包含非索引字段,所以數據結構較小,系統能快速遍歷。我們知道索引時b+樹結構,系統能很容易的知道866613,位於索引樹的位置。
##查詢語句 select id from product limit 866613, 20 ##優化方式一 SELECT * FROM product WHERE ID > =(select id from product limit 866613, 1) limit 20 ##優化方式二 SELECT * FROM product a JOIN (select id from product limit 866613, 20) b ON a.ID = b.id
局限性:
依賴於主鍵的自增長特性。
不適合復雜查詢條件的分頁邏輯,復雜查詢條件很難做到,索引包含全部查詢字段,容易漏掉部分數據。
方法三:
復合索引:其原理同樣是索引覆蓋的思想,只不過是其以查詢條件的一份作為索引,最終的索引字段是主鍵id。這種場景嚴格依賴於索引的順序。查詢的結果也不能包含非索引字段,需再走一次子查詢。
可以參考博客:https://blog.csdn.net/yalishadaa/article/details/72861309
關於深度分頁:
針對復雜的查詢邏輯,一般從數據的 偏移量着手,減少偏移量的定位時間。
簡單的查詢邏輯,可以從索引覆蓋的思想着手,先確定查詢數據的主鍵id,再由id找相關的數據,索引能解決的 就不要加給業務邏輯了。