2014-05-02 76 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}); 
});