在前面文章曾經提到,在MongoDB中一起使用$or和sort()時,查詢效能會很差,詳見:http://www.cnblogs.com/xinghebuluo/archive/2011/12/01/2270590.html
在mongodb的計劃中,2.5.w版本中可能會修改這個bug。
我的項目中也遇到了這個問題,後來自己想了一個解決方案,暫時規避了這個問題,現在把這個方案分享出來,和大家討論一下.
這個解決方案是受到了mongos的原始碼的啟示,眾所周知mongodb是分布式架構,那麼在我們使用mongos查詢並使用排序的時候,mongos需要把查詢請求發送給各個shard,並將每個shard的查詢結果
存放在一個隊列中(隊列中已經排好序)。這裡假定有2個shard(多個shard的原理是一樣的),查詢條件為{“age”:20},排序條件為:{"time":1},mongos實現如下:
1. mongos首先向兩個shard發送查詢排序命令。
2.兩個shard返回結果是排序後的兩個隊列,。
3.用戶端在取記錄時,mongos取出兩個隊列的第一個元素,判斷time值小的記錄返回給用戶端。
4.用戶端再取記錄時,重複步驟3,從兩個隊列中取time值小的記錄返回給用戶端。
正是受到mongos的啟發,在遇到or查詢並sort的情況時,把or的查詢條件分解為多次查詢,然後實現了一個查詢類,裡面儲存了list<DBObject q>,然後向mongos發起多次查詢排序請求,
此時得到多個cursor,此時的cursor就類似於上面的隊列,即此時得到了多個排序好的隊列,然後經過簡單比較後,依次把記錄返回給用戶端。
例如,此時查詢{"$or":[{"age":20},{"name":"li"}]},排序條件為{"Time":1},可以分解為2次查詢:{"age":20},{"name":"li"},執行查詢後,得到兩個cursor,即兩個隊列,如下:、
此時就可以重複mongos的步驟了,在用戶端取記錄時,對隊列(cursor)中的第一個元素做比較,取出time值最小的記錄返回給用戶端。
該解決方案的優點如下:
1.可以使用索引,速度很快。
2.封裝類後,可以供多個業務使用。
缺點如下:
1. 每個隊列中會緩衝一些記錄,這無形中造成了一些流量浪費和記憶體浪費。
上面是我對這個方案的整體思路,歡迎大家討論。