面試題:在數據量很大的狀況下,怎麼實現深度分頁?
你們在面試時,或者準備面試中可能會遇到上述的問題,大多的回答基本上是分庫分表建索引
,這是一種很標準的正確回答
,但現實老是很骨感,因此面試官通常會追問你一句,<font color="red">如今工期不足,人員不足,該怎麼實現深度分頁?</font>mysql
這個時候沒有實際經驗的同窗基本麻爪,So,請聽我娓娓道來。面試
首先必須明確一點:深度分頁能夠作,可是<font color="red">深度隨機跳頁絕對須要禁止。</font>sql
上一張圖:數據庫
大家猜,我點一下第142360
頁,服務會不會爆炸?bash
像MySQL
,MongoDB
數據庫還好,自己就是專業的數據庫,處理的很差,最多就是慢,但若是涉及到ES
,性質就不同了,咱們不得不利用 SearchAfter
Api,去循環獲取數據,這就牽扯到內存佔用的問題,若是當時代碼寫的不優雅,直接就可能致使內存溢出。併發
從技術的角度淺顯的聊一聊爲何不能容許隨機深度跳頁,或者說爲何不建議深度分頁高併發
分頁的基本原理:post
SELECT * FROM test ORDER BY id DESC LIMIT 10000, 20;
LIMIT 10000 , 20的意思掃描知足條件的10020行,扔掉前面的10000行,返回最後的20行。若是是LIMIT 1000000 , 100,須要掃描1000100 行,在一個高併發的應用裏,每次查詢須要掃描超過100W行,不炸纔怪。性能
分頁的基本原理:測試
db.t_data.find().limit(5).skip(5);
一樣的,隨着頁碼的增大,skip 跳過的條目也會隨之變大,而這個操做是經過 cursor 的迭代器來實現的,對於cpu的消耗會很是明顯,當頁碼很是大時且頻繁時,必然爆炸。
從業務的角度來講,ElasticSearch
不是典型的數據庫,它是一個搜索引擎,若是在篩選條件下沒有搜索出想要的數據,繼續深度分頁也不會找到想要的數據,退一步講,假如咱們把ES
做爲數據庫來使用進行查詢,在進行分頁的時候必定會遇到max_result_window
的限制,看到沒,官方都告訴你最大偏移量限制是一萬。
查詢流程:
由此能夠看出爲何要限制偏移量,另外,若是使用 Search After
這種滾動式API進行深度跳頁查詢,也是同樣須要每次滾動幾千條,可能一共須要滾動上百萬,千萬條數據,就爲了最後的20條數據,效率可想而知。
<font color="red">俗話說的好,技術解決不了的問題,就由業務來解決!</font>
在實習的時候信了產品的邪,必須實現深度分頁 + 跳頁,現在必須撥亂反正
,業務上必須有以下更改:
滾動顯示參考圖:
小規模跳頁參考圖:
短期內快速解決的方案主要是如下幾點:
原分頁SQL:
# 第一頁 SELECT * FROM `year_score` where `year` = 2017 ORDER BY id limit 0, 20; # 第N頁 SELECT * FROM `year_score` where `year` = 2017 ORDER BY id limit (N - 1) * 20, 20;
經過上下文關係,改寫爲:
# XXXX 表明已知的數據 SELECT * FROM `year_score` where `year` = 2017 and id > XXXX ORDER BY id limit 20;
在 沒內鬼,來點乾貨!SQL優化和診斷 一文中提到過,LIMIT會在知足條件下中止查詢,所以該方案的掃描總量會急劇減小,效率提高Max!
方案和MySQL
相同,此時咱們就能夠隨用所欲的使用 FROM-TO
Api,並且不用考慮最大限制的問題。
方案基本相似,基本代碼以下:
相關性能測試:
若是你沒有槓過產品經理,又該怎麼辦呢,不要緊,還有一絲絲的機會。
在 SQL優化 一文中還提到過MySQL
深度分頁的處理技巧,代碼以下:
# 反例(耗時129.570s) select * from task_result LIMIT 20000000, 10; # 正例(耗時5.114s) SELECT a.* FROM task_result a, (select id from task_result LIMIT 20000000, 10) b where a.id = b.id; # 說明 # task_result表爲生產環境的一個表,總數據量爲3400萬,id爲主鍵,偏移量達到2000萬
該方案的核心邏輯即基於聚簇索引
,在不經過回表
的狀況下,快速拿到指定偏移量數據的主鍵ID,而後利用聚簇索引
進行回表查詢,此時總量僅爲10條,效率很高。
所以咱們在處理MySQL
,ES
,MongoDB
時,也能夠採用同樣的辦法:
瑕疵:當偏移量很是大時,耗時較長,如文中的 5s
參考文章:MongoDB中文社區
感謝 @程大設計師 爲我傾情設計的二維碼😜
若是以爲對你有用的話,不要忘記點個贊啊~