採用Seek Method加速分頁

凡事作過頁面的,通常對分頁不會陌生,也不會以爲它有多難:就是limit + offset的組合就能夠了呀。可是,危險每每都是從最不起眼的地方開始的。在這裏,我先說一下我以前在用MongoDB時遇到的問題。這類問題一樣會出如今這種分頁方式上。sql

當時,我須要對於MongoDB中的數據進行處理,每次處理一批,也至關因而按頁來操做數據啦。這個沒啥難度,直接使用API中的find + skip + limit就能夠輕易搞定。迅速把程序寫完以後就開始拿產品庫開搞了。剛開始一切正常,可過了沒多久,就發現整個程序的性能降低了。進入Mongo一查,發現是Table Scan。哇,那個collection中有上千萬的數據啊!性能

此處略去3000字。fetch

總之,問題最後解決了,程序又運行如飛。而解決之道很簡單:只用find + limit,再也不使用skip(緣由本身想)。只不過在find中加了一個條件:上一批的最後一個document的_id。整個代碼形似(groovy代碼):code

if (docId) {
    batch = collection.find(['_id': ['$gt': docId]] as Document).limit(BATCH_SIZE)
} else {
    batch = collection.find().limit(BATCH_SIZE)
}
docId = batch[-1]['_id']

它的原理很簡單,其實就是利用能夠利用的index來加速分頁。這種思想跟今天看到的文章的思路一模一樣,再也不使用offset,尋找能達到一樣效果的index,用它來助力搜索。所以,文中給出的方案跟上面的代碼相似:blog

SELECT ...
  FROM ...
 WHERE ...
   AND id < ?last_seen_id
 ORDER BY id DESC
 FETCH FIRST 10 ROWS ONLY

這種分頁方式被稱爲「seek method」,其中的id被稱爲「seek predicate」。典型的seek predicate還能夠是日期。須要提醒的是,seek predicate上須要有index纔有意義,並且它能夠有多列!採用這種方式的分頁能夠避免上述分頁的潛在危險:當頁數達到必定量以後,分頁速度會嚴重降低。ip

關於seek method,還能夠參考下面的文章:get

相關文章
相關標籤/搜索