分頁查詢的幾種思路

背景:今天發現一個獲取list的接口返回空的數據,一看日誌發現是超時了,不由得就分析起來了原因,看了代碼發現應該是懷疑兩個地方有些問題,一個是獲取數據的地方,一個是獲取count的地方。

於是連上只讀庫測試查詢語句,發現了count那裏真的很慢,我用的是mongo,因爲符合查詢結果的條件就很多,所以count就很慢,索引也不能減少時間,奇怪了,難道mongo的count真的要一條條數嗎。。。

查了下count爲什麼那麼慢,也沒有找到什麼值得信服的理由,但有人建議,count另存,不要查詢條件去count。好吧,這是一個優化點。然後我的分頁用的是最簡單的方法,下面開始說下常見的分頁思路,注意前提是排除獲取count的消耗,下面只說的是分頁的思路。

一、 skip and limit

最簡單的一種,不需要額外的處理,直接skip就完事了。當然缺點也很明顯,當數據量比較大的時候,這裏就會有性能問題,假如現在在1w頁的地方,每頁10條,我想到1w1頁,此時從界面來看我只是簡單的翻一頁,但是db 查詢要skip10w條,這個就可划不來了。而且這種每次都需要返回總count,便於顯示多少頁,比如count結果是10w條,每頁10條,那麼就有1w頁。

二、gt lt 某個字段

僞代碼就是db.find({id:{$gt:xxx}}).sort({id:1}).limit(pagesize) 

前置條件:需要將每頁的最後一個id返回給前端(往前翻的是要就要傳每頁的第一個id,並且使用lt, sort id : -1),然後翻頁的時候前端傳過來。當然你也可以指定別的字段,比如時間戳等

優點:顯而易見,只需要在id上建索引,想去哪就去哪,性能沒問題

缺點:1.需要保證你比較的那個字段唯一,不能有重複的,假如有多個重複的id,你使用gt id,就跳過了後面好多個相等id的內容,但是有人該說了,使用gte吧,那怕是可能永遠也翻不過去頁了。

2.不能跳到某頁,只能一頁頁的翻,也不知道有多少頁,除非你把count單獨存。

三、雙劍合璧

那麼我們有沒有一種方法既能跳頁,顯示總頁數,也能不會有性能問題呢?還是有的,雖然並不是那麼完美,正如標題所說,雙劍合璧,即把上面兩種方法的優點結合,組合成第三種

僞代碼

var current_id  int

N 當前頁與要翻頁頁數的差的絕對值 ,page_size就是每頁顯示的條數

比如要從第三頁到第五頁,每頁顯示10條,N = 2,page_size=10, current_id就是第三頁的第一個id 

1.向前翻頁   db.find({id:{$gte:current_id}}).skip(N*page_size).limit(page_size).sort({id:1})

同理第五頁到第三頁,每頁顯示10條,此時N=2, page_size=10,current_id就是第五頁的第一個id

2.向後翻頁   db.find({id:{$lt:current_id}}).skip((N-1)*page_size).limit(page_size).sort({id:-1})

缺點也明顯,就是一下跳到最後一頁,還是有點慢的,不過相鄰頁之間無壓力

常用於下面的實現,參考鏈接https://stackoverflow.com/questions/9703319/mongodb-ranged-pagination

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章