在前面文章曾經提到,在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. 每個隊列中會緩存一些記錄,這無形中造成了一些流量浪費和內存浪費。
上面是我對這個方案的整體思路,歡迎大家討論。