2014-05-02 78 views
3

我有一個分片集「my_collection」結構如下:加快MongoDB的聚集

{ 
    "CREATED_DATE" : ISODate(...), 
    "MESSAGE" : "Test Message", 
    "LOG_TYPE": "EVENT" 
} 

MongoDB的環境是分片與2個碎片。上述集合在LOG_TYPE上使用散列分片鍵進行分片。 LOG_TYPE屬性還有另外7種可能性。

我在「my_collection」 1萬份文件,我試圖找到使用以下查詢基礎上,LOG_TYPE文件數:

db.my_collection.aggregate([ 
    { "$group" :{ 
     "_id": "$LOG_TYPE", 
     "COUNT": { "$sum":1 } 
    }} 
]) 

但是,這讓我產生約3秒鐘。有什麼辦法可以改善嗎?另外,當我運行explain命令時,它顯示沒有使用索引。組命令是否不使用索引?

+0

在聚集命令willnot使用索引該集團運營商,也是上述acurrate是表示該youonly有您的收藏三個字段?信息有多大? – Sammaye

+0

由於您事實上彙集了您的集合中的所有文檔,因此索引將毫無用處,除非它是生成涵蓋查詢的索引,但我不確定這是否有幫助。 MongoDB仍然會做分散和收集操作 – Sammaye

+0

@Sammaye這是不正確的。如果這是第一個也是唯一的階段,那麼索引將被選中。看到'explain'輸出(實際上來自2.4.8),但從一般前提來看,優化器會將其解決。出於同樣的原因,您給出的答案實際上沒有進一步優化過程。如果您瞭解代碼的實際工作方式,那麼優化器中就會隱含預測。 –

回答

0

在MongoDB中可以做的事情數量有限,最終可能是一個超出MongoDB本身的物理問題,可能會導致configsrvs不及時響應或導致結果從碎片太慢了。

但是,您可能可以通過使用覆蓋查詢來解決一些執行中的問題。既然你實際上在LOG_TYPE上分割,你將已經有一個索引(在你可以分割它之前需要),不僅如此,而且聚合框架會自動添加projection,這樣做無能爲力。

MongoDB可能必須與每個分片進行通信以獲得結果,否則稱爲分散和收集操作。

$group自己不會使用索引。

這是我的結果在2.4.9:

> db.t.ensureIndex({log_type:1}) 
> db.t.runCommand("aggregate", {pipeline: [{$group:{_id:'$log_type'}}], explain: true}) 
{ 
     "serverPipeline" : [ 
       { 
         "query" : { 

         }, 
         "projection" : { 
           "log_type" : 1, 
           "_id" : 0 
         }, 
         "cursor" : { 
           "cursor" : "BasicCursor", 
           "isMultiKey" : false, 
           "n" : 1, 
           "nscannedObjects" : 1, 
           "nscanned" : 1, 
           "nscannedObjectsAllPlans" : 1, 
           "nscannedAllPlans" : 1, 
           "scanAndOrder" : false, 
           "indexOnly" : false, 
           "nYields" : 0, 
           "nChunkSkips" : 0, 
           "millis" : 0, 
           "indexBounds" : { 

           }, 
           "allPlans" : [ 
             { 
               "cursor" : "BasicCursor", 
               "n" : 1, 
               "nscannedObjects" : 1, 
               "nscanned" : 1, 
               "indexBounds" : { 

               } 
             } 
           ], 
           "server" : "ubuntu:27017" 
         } 
       }, 
       { 
         "$group" : { 
           "_id" : "$log_type" 
         } 
       } 
     ], 
     "ok" : 1 
} 

這是從2.6結果:

> use gthtg 
switched to db gthtg 
> db.t.insert({log_type:"fdf"}) 
WriteResult({ "nInserted" : 1 }) 
> db.t.ensureIndex({log_type: 1}) 
{ "numIndexesBefore" : 2, "note" : "all indexes already exist", "ok" : 1 } 
> db.t.runCommand("aggregate", {pipeline: [{$group:{_id:'$log_type'}}], explain: true}) 
{ 
     "stages" : [ 
       { 
         "$cursor" : { 
           "query" : { 

           }, 
           "fields" : { 
             "log_type" : 1, 
             "_id" : 0 
           }, 
           "plan" : { 
             "cursor" : "BasicCursor", 
             "isMultiKey" : false, 
             "scanAndOrder" : false, 
             "allPlans" : [ 
               { 
                 "cursor" : "BasicCursor", 
                 "isMultiKey" : false, 
                 "scanAndOrder" : false 
               } 
             ] 
           } 
         } 
       }, 
       { 
         "$group" : { 
           "_id" : "$log_type" 
         } 
       } 
     ], 
     "ok" : 1 
} 
+0

增加的項目操作降低了性能。它現在花費大約0.5秒多。我認爲,正如你所說,mongoDB必須執行分散和收集操作,並且不能使用索引進行組操作。 –

+0

@ cj0809在您選擇的輸出屬性中,投影實際上是「自動的」。額外的通行證實際上是強制通過,雖然你收集或優化工作集,因此不是一個好主意,除非你已經減少到你想要的工作集。 –

8

目前在什麼聚合框架可以做,以提高性能的一些限制您的查詢,但您可以通過以下方式提供幫助:

db.my_collection.aggregate([ 
    { "$sort" : { "LOG_TYPE" : 1 } }, 
    { "$group" :{ 
     "_id": "$LOG_TYPE", 
     "COUNT": { "$sum":1 } 
    }} 
]) 

通過添加排序在LOG_TYPE上,您將「強制」優化器使用LOG_TYPE上的索引來按順序獲取文檔。這將以多種方式提高性能,但取決於所用版本的不同。

如果您有數據進入$ group階段排序,那麼在真實數據上,它會提高總計累計效率。您可以在$ sort中看到不同的查詢計劃,它將使用分片索引。這在實際性能上的改進將取決於每個「桶」中的值的數量 - 一般來說,LOG_TYPE只有7個不同的值使其成爲極差的分片密鑰,但這確實意味着下列代碼可能是很多甚至比優化的聚合速度快:

db.my_collection.distinct("LOG_TYPE").forEach(function(lt) { 
    print(db.my_collection.count({"LOG_TYPE":lt}); 
});