无法在MongoDB中创建覆盖查询

时间:2015-10-23 06:26:26

标签: mongodb mongodb-query mongo-java nosql

我面临创建覆盖查询的问题。我使用的是Mongo 3最新版本。这是我的示例数据,我已将10006个文档插入MongoDB。

db.order.insert({ _id: 1, cust_id: "abc1", ord_date: ISODate("2012-11-02T17:04:11.102Z"), status: "A", amount: 50 })
db.order.insert({ _id: 2, cust_id: "xyz1", ord_date: ISODate("2013-10-01T17:04:11.102Z"), status: "A", amount: 100 })
db.order.insert({ _id: 3, cust_id: "xyz1", ord_date: ISODate("2013-10-12T17:04:11.102Z"), status: "D", amount: 25 })
db.order.insert({ _id: 4, cust_id: "xyz1", ord_date: ISODate("2013-10-11T17:04:11.102Z"), status: "D", amount: 125 })
db.order.insert({ _id: 5, cust_id: "abc1", ord_date: ISODate("2013-11-12T17:04:11.102Z"), status: "A", amount: 25 })

对于涵盖查询,查询中的所有字段都是索引的一部分,因此我创建了status,ord_date,cust_id和amount字段的索引,如:

db.orders.createIndex({status: 1})
db.orders.createIndex({amount: 1})
db.orders.createIndex({ord_date: 1})
db.orders.createIndex({cust_id: 1})

我执行了以下查询。

          db.orders.find(
                 {status : "A"},{ord_date : 1, cust_id : 1}
          ).sort({ amount: -1 }).explain()

但是这个解释查询返回executionStats.totalDocsExamined = 200而不是executionStats.totalDocsExamined = 0.这意味着当我执行查询时它是扫描文档。在Mongo 3中,我们可以使用executionStats.totalDocsExamined而不是indexOnly来检查覆盖查询的索引。

任何人都可以建议我在覆盖查询中做错了吗?

以下是Markus的指数建议后的输出:

{
"queryPlanner" : {
    "plannerVersion" : 1,
    "namespace" : "local.orders",
    "indexFilterSet" : false,
    "parsedQuery" : {
        "status" : {
            "$eq" : "A"
        }
    },
    "winningPlan" : {
        "stage" : "PROJECTION",
        "transformBy" : {
            "_id" : 1,
            "ord_date" : 1,
            "cust_id" : 1
        },
        "inputStage" : {
            "stage" : "SORT",
            "sortPattern" : {
                "amount" : -1
            },
            "inputStage" : {
                "stage" : "COLLSCAN",
                "filter" : {
                    "status" : {
                        "$eq" : "A"
                    }
                },
                "direction" : "forward"
            }
        }
    },
    "rejectedPlans" : [ ]
},
"executionStats" : {
    "executionSuccess" : true,
    "nReturned" : 10004,
    "executionTimeMillis" : 70,
    "totalKeysExamined" : 0,
    "totalDocsExamined" : 10018,
    "executionStages" : {
        "stage" : "PROJECTION",
        "nReturned" : 10004,
        "executionTimeMillisEstimate" : 70,
        "works" : 20026,
        "advanced" : 10004,
        "needTime" : 10021,
        "needFetch" : 0,
        "saveState" : 157,
        "restoreState" : 157,
        "isEOF" : 1,
        "invalidates" : 0,
        "transformBy" : {
            "_id" : 1,
            "ord_date" : 1,
            "cust_id" : 1
        },
        "inputStage" : {
            "stage" : "SORT",
            "nReturned" : 10004,
            "executionTimeMillisEstimate" : 70,
            "works" : 20026,
            "advanced" : 10004,
            "needTime" : 10020,
            "needFetch" : 0,
            "saveState" : 157,
            "restoreState" : 157,
            "isEOF" : 1,
            "invalidates" : 0,
            "sortPattern" : {
                "amount" : -1
            },
            "memUsage" : 960384,
            "memLimit" : 33554432,
            "inputStage" : {
                "stage" : "COLLSCAN",
                "filter" : {
                    "status" : {
                        "$eq" : "A"
                    }
                },
                "nReturned" : 10004,
                "executionTimeMillisEstimate" : 10,
                "works" : 10020,
                "advanced" : 10004,
                "needTime" : 15,
                "needFetch" : 0,
                "saveState" : 157,
                "restoreState" : 157,
                "isEOF" : 1,
                "invalidates" : 0,
                "direction" : "forward",
                "docsExamined" : 10018
            }
        }
    },
    "allPlansExecution" : [ ]
},
"serverInfo" : {
    "host" : "pcd32",
    "port" : 27017,
    "version" : "3.0.7",
    "gitVersion" : "6ce7cbe8c6b899552dadd907604559806aa2esd5"
}

}

2 个答案:

答案 0 :(得分:1)

虽然有index intersections in MongoDB,但使用它们可能非常棘手。但是,坚持一个经验法则是一个相当安全的赌注:

  

创建MongoDB查询时,假设一次只能使用一个索引

对于covered queries尤其如此,详见文档:

  

当以下两项都适用时,索引会涵盖查询:

     
      
  • 查询中的所有字段都是索引的一部分,

  •   
  • 结果中返回的所有字段都在同一索引中。

  •   

拥有compound index没有缺点,经过精心设计,因为只使用该索引的部分内容的查询也可以使用它。

因此,为了覆盖您的查询,您需要在索引中输入所有键。由于您没有limit the fields returned(MongoDB术语中的“投影”),我假设您还需要返回_id字段。此外,您的索引应该反映您的排序顺序。所以你的索引应该是这样的:

db.orders.createIndex({_id:1,status:1, ord_date:1,cust_id:1,amount:-1})

查询。订单很重要,因此为了充分利用新创建的索引,其他查询应遵循相同的字段顺序。

答案 1 :(得分:1)

如果您还需要_id字段,则下面的复合索引应该为您提供一个覆盖查询:

 db.order.createIndex({status:1, amount:-1, ord_date:1, cust_id :1, _id:1})

如果您不需要_id字段,请在_id : 0中使用find(),以便不检索_id,也可以将其从索引中删除。 请注意,在覆盖查询中,与正在执行的实际查询相比,字段的排序对于在查询执行中使用的索引非常重要。