Mongodb.aggregate()忽略了索引

时间:2017-03-21 11:57:04

标签: mongodb

我收集了大致跟随结构的存档任务

{
    "_id" : "job-id_00000001_2017-03-17T21:30:38.510Z",
    "jobId" : "job-id",
    "result" : {
        "status" : "ok"
    },
    "..." : "..."
}

最重要的是我有

指数
jobId: 1
result.status: 1
jobId: 1, result.status: 1

在某些用例中,我需要更频繁地更新统计信息(map:job-id - > status - > count),当我执行此聚合函数时......

db.getCollection('jobs_archive').aggregate([
            {$group: {
                _id: {jobId: "$jobId", status: "$result.status"},
                count: { $sum: 1 }
            }}
        ], {explain: true} )

...它在1.2ml行上运行~4秒,这是不可接受的长。 explain: true我得到了......

"queryPlanner" : {
    "plannerVersion" : 1,
    "namespace" : "db.jobs_archive",
    "indexFilterSet" : false,
    "parsedQuery" : {},
    "winningPlan" : {
        "stage" : "COLLSCAN",
        "direction" : "forward"
    },
    "rejectedPlans" : []
}    

...而且COLLSCAN意味着Mongo不使用索引中的数据,但复合索引jobId: 1, result.status: 1中的所有字段都可用。

有没有办法优化aggregate查询的效果?我做错了吗?

由Ori Dar回答的附录

在深入研究文档之后,我已经注意到"涵盖的查询",在这种情况下应该使用我应该使用的功能。似乎不是。

涵盖查询 https://docs.mongodb.com/manual/core/query-optimization/#covered-query

  

覆盖查询是一个完全可以使用的查询   索引,而不必检查任何文件。索引涵盖了一个   当以下两种情况都适用时查询:

     
      
  • 查询中的所有字段都是索引的一部分,
  •   
  • 结果中返回的所有字段都在同一索引中。
  •   
     

...

     

因为索引包含查询所需的所有字段,所以MongoDB   可以匹配查询条件并仅使用返回结果   索引。

     

仅查询索引比查询文档快得多   在指数之外。索引键通常小于   他们编目的文档,索引通常在RAM或   按顺序放在磁盘上。

来自Mongo的更多奇怪

(1) db.getCollection('jobs_archive').find({"jobId" : "job-id"}).count()
--> 0.375sec, count = 430000

(2) db.getCollection('archive').find({"jobId" : "job-id", "result.status": "ok"}).count()
--> 1.400sec, count = 430000

explain()

  1. winnerPlan:IXSCAN /" indexName" :" jobId_1_result.status_1"
  2. winnerPlan:IXSCAN /" indexName" :" jobId_1"
  3. 所以,我会使用' query()。count()'对于每个工作ID +状态'的组合(如果是正确使用指数的话,是6 * 5),但是在这种情况下似乎也不是。当我指定两个键' jobId + result.status'复合索引不用于count() ...当我在查询中只指定一个jobId时,使用复合索引... r-r-r-r

    注意:Mongo"版本" :" 3.4.2",Ubuntu 16

1 个答案:

答案 0 :(得分:0)

来自Pipeline Operators and Indexes

  
    

管道运算符和索引¶

         

$ match和$ sort管道运算符可以在管道开头出现时利用索引。

  

MongoDB 不会使用$group

的索引

在处理所有文档的意义上,您正在进行全面扫描。因此,使用索引会导致每个文档的重复查找:一次是索引,一次是文档本身,所以重点是什么。

因此,只有在首先使用$match过滤器缩小结果范围时,才能使用索引。

作为旁注,{jobId: 1}索引是多余的。

查询优化器可以使用{jobId: 1, result.status: 1}索引使用以下模式进行查询:db.jobs_archive.find({jobId: n})

请参阅Prefixes