为什么计算查询获取文档?

时间:2017-08-25 08:39:47

标签: mongodb

我有一个像MongoDB这样的文档:

  • objectId的集合数组
  • 一个bool for draft
  • 一个bool for deleted

Exsample:

"_id" : "55689be772ba931a30c87fd8",
"Draft" : false,
"Deleted" : false,
"productsId" : [
    ObjectId("55688d7a72ba931bf430edf5"),
    ObjectId("55688d7a72ba931bf430edf8"),
    ObjectId("55688d7a72ba931bf430edf0"),
    ObjectId("55688d7a72ba931bf430edee")
]

我有一个索引:

db.getCollection("mycolection").createIndex({ "Deleted": 1, "Draft": 1, "productsId": 1 }, { "name": "_deleted_draft_productsId" })

为什么我执行此查询时:

db.mycolection.explain("executionStats").count({productsId: ObjectId('55688d7a72ba931bf430edf4'),Draft: { $ne: true }, Deleted: { $ne: true } })

我通过totalKeysExamined:687收到此统计信息:

"executionStats" : {
        "executionSuccess" : true,
        "nReturned" : 685,
        "executionTimeMillis" : 3,
        "totalKeysExamined" : 687,
        "totalDocsExamined" : 685,
        "executionStages" : {
            "stage" : "FETCH",
            "filter" : {
                "$and" : [
                    {
                        "$nor" : [
                            {
                                "Deleted" : {
                                    "$eq" : true
                                }
                            }
                        ]
                    },
                    {
                        "$nor" : [
                            {
                                "Draft" : {
                                    "$eq" : true
                                }
                            }
                        ]
                    }
                ]
            },
            "nReturned" : 685,
            "executionTimeMillisEstimate" : 0,
            "works" : 687,
            "advanced" : 685,
            "needTime" : 1,
            "needYield" : 0,
            "saveState" : 7,
            "restoreState" : 7,
            "isEOF" : 1,
            "invalidates" : 0,
            "docsExamined" : 685,
            "alreadyHasObj" : 0,
            "inputStage" : {
                "stage" : "IXSCAN",
                "nReturned" : 685,
                "executionTimeMillisEstimate" : 0,
                "works" : 687,
                "advanced" : 685,
                "needTime" : 1,
                "needYield" : 0,
                "saveState" : 7,
                "restoreState" : 7,
                "isEOF" : 1,
                "invalidates" : 0,
                "keyPattern" : {
                    "productsId" : 1,
                    "Deleted" : 1,
                    "Draft" : 1
                },
                "indexName" : "_productsId_deleted_draft",
                "isMultiKey" : true,
                "multiKeyPaths" : {
                    "productsId" : [
                        "productsId"
                    ],
                    "Deleted" : [ ],
                    "Draft" : [ ]
                },
                "isUnique" : false,
                "isSparse" : false,
                "isPartial" : false,
                "indexVersion" : 2,
                "direction" : "forward",
                "indexBounds" : {
                    "productsId" : [
                        "[ObjectId('55688d7a72ba931bf430edf4'), ObjectId('55688d7a72ba931bf430edf4')]"
                    ],
                    "Deleted" : [
                        "[MinKey, true)",
                        "(true, MaxKey]"
                    ],
                    "Draft" : [
                        "[MinKey, true)",
                        "(true, MaxKey]"
                    ]
                },
                "keysExamined" : 687,
                "seeks" : 2,
                "dupsTested" : 685,
                "dupsDropped" : 0,
                "seenInvalidated" : 0
            }
        }
    }

但如果我尝试以这种方式删除draftdeleted bool字段:

db.Redazionale.explain("executionStats").count({IdProdotti: ObjectId('55688d7a72ba931bf430edf4') })

我使用totalDocsExamined:0获得此统计信息,这也是我在之前的查询中所期望的

"executionStats" : {
        "executionSuccess" : true,
        "nReturned" : 0,
        "executionTimeMillis" : 0,
        "totalKeysExamined" : 690,
        "totalDocsExamined" : 0,
        "executionStages" : {
            "stage" : "COUNT",
            "nReturned" : 0,
            "executionTimeMillisEstimate" : 0,
            "works" : 690,
            "advanced" : 0,
            "needTime" : 689,
            "needYield" : 0,
            "saveState" : 5,
            "restoreState" : 5,
            "isEOF" : 1,
            "invalidates" : 0,
            "nCounted" : 689,
            "nSkipped" : 0,
            "inputStage" : {
                "stage" : "COUNT_SCAN",
                "nReturned" : 689,
                "executionTimeMillisEstimate" : 0,
                "works" : 690,
                "advanced" : 689,
                "needTime" : 0,
                "needYield" : 0,
                "saveState" : 5,
                "restoreState" : 5,
                "isEOF" : 1,
                "invalidates" : 0,
                "keysExamined" : 690,
                "keyPattern" : {
                    "productsId" : 1,
                    "Deleted" : 1,
                    "Draft" : 1
                },
                "indexName" : "_productsId_deleted_draft",
                "isMultiKey" : true,
                "multiKeyPaths" : {
                    "productsId" : [
                        "productsId"
                    ],
                    "Deleted" : [ ],
                    "Draft" : [ ]
                },
                "isUnique" : false,
                "isSparse" : false,
                "isPartial" : false,
                "indexVersion" : 2,
                "indexBounds" : {
                    "startKey" : {
                        "productsId" : ObjectId("55688d7a72ba931bf430edf4"),
                        "Deleted" : MinKey,
                        "Draft" : MinKey
                    },
                    "startKeyInclusive" : true,
                    "endKey" : {
                        "productsId" : ObjectId("55688d7a72ba931bf430edf4"),
                        "Deleted" : MaxKey,
                        "Draft" : MaxKey
                    },
                    "endKeyInclusive" : true
                }
            }
        }
    }

更新

我上传了一个文件转储来创建整个数据库的一小部分。 click here to download

并尝试这些查询:

db.Redazionale.explain("executionStats").count({ IdProdotti: ObjectId('55688d7a72ba931bf430edf4'),Draft: { $ne: true }, Deleted: { $ne: true } })

db.Redazionale.explain("executionStats").count({ IdProdotti: ObjectId('55688d7a72ba931bf430edf4') })

1 个答案:

答案 0 :(得分:0)

问题是像Draft: { $ne: true }这样的查询实际上是具有以下范围的范围查询:

"Draft" : [
    "[MinKey, true)",
    "(true, MaxKey]"
]

所以您的查询结果有3个边界:

           "indexBounds" : {
                "productsId" : [
                    "[ObjectId('55688d7a72ba931bf430edf4'), ObjectId('55688d7a72ba931bf430edf4')]"
                ],
                "Deleted" : [
                    "[MinKey, true)",
                    "(true, MaxKey]"
                ],
                "Draft" : [
                    "[MinKey, true)",
                    "(true, MaxKey]"
                ]
            },

如果您有多个选择索引,则由优化者选择最具选择性的索引。

在你的情况下,它决定productsId是最有效的,这是一个公平的选择。它使用复合索引productsId的{​​{1}}部分来获取相关文档,然后通过其他2个字段对其进行过滤。

删除3个范围中的2个允许使用COUNT_SCAN。将布尔范围转换为精确比较也是如此。像

这样的查询
_productsId_deleted_draft

COUNT_SCAN是否可以使用以下边界:

db.mycolection.explain("executionStats").count({
    productsId: ObjectId('55688d7a72ba931bf430edf4'),
    Draft: false, 
    Deleted: false 
})

问题是 "indexBounds" : { "startKey" : { "productsId" : ObjectId("55688d7a72ba931bf430edf4"), "Deleted" : false, "Draft" : false }, "startKeyInclusive" : true, "endKey" : { "productsId" : ObjectId("55688d7a72ba931bf430edf4"), "Deleted" : false, "Draft" : false }, "endKeyInclusive" : true } 只有当所有文档都有Draft: { $ne: true }字段时才等同于Draft: false,因此可能是确保布尔字段始终存在的选项。甚至可以使用document validation强制执行它。这实际上取决于优化带来了多少好处。