为什么MongoDB不同的查询计划显示不同的nReturned值?

时间:2017-08-04 02:37:17

标签: mongodb indexing mongodb-query database-performance query-performance

我的faults数据库中有一个集合MongoDB,每个文档都包含以下字段:rack_nametimestamp

为了测试和比较性能,我创建了这两个索引:

rack -> {'rack_name': 1}

time -> {'timestamp': 1}

现在我用explain()执行以下查询:

db.faults.find({
    'rack_name': {
        $in: [ 'providence1', 'helena2' ]
    }, 
    'timestamp': {
        $gt: 1501548359000
    }
})
.explain('allPlansExecution') 

以下是结果:

 {
"queryPlanner" : {
    "plannerVersion" : 1,
    "namespace" : "quicktester_clone.faults",
    "indexFilterSet" : false,
    "parsedQuery" : {
        "$and" : [ 
            {
                "timestamp" : {
                    "$gt" : 1501548359000.0
                }
            }, 
            {
                "rack_name" : {
                    "$in" : [ 
                        "helena2", 
                        "providence1"
                    ]
                }
            }
        ]
    },
    "winningPlan" : {
        "stage" : "FETCH",
        "filter" : {
            "timestamp" : {
                "$gt" : 1501548359000.0
            }
        },
        "inputStage" : {
            "stage" : "IXSCAN",
            "keyPattern" : {
                "rack_name" : 1
            },
            "indexName" : "rack",
            "isMultiKey" : false,
            "multiKeyPaths" : {
                "rack_name" : []
            },
            "isUnique" : false,
            "isSparse" : false,
            "isPartial" : false,
            "indexVersion" : 2,
            "direction" : "forward",
            "indexBounds" : {
                "rack_name" : [ 
                    "[\"helena2\", \"helena2\"]", 
                    "[\"providence1\", \"providence1\"]"
                ]
            }
        }
    },
    "rejectedPlans" : [ 
        {
            "stage" : "FETCH",
            "filter" : {
                "rack_name" : {
                    "$in" : [ 
                        "helena2", 
                        "providence1"
                    ]
                }
            },
            "inputStage" : {
                "stage" : "IXSCAN",
                "keyPattern" : {
                    "timestamp" : 1
                },
                "indexName" : "time",
                "isMultiKey" : false,
                "multiKeyPaths" : {
                    "timestamp" : []
                },
                "isUnique" : false,
                "isSparse" : false,
                "isPartial" : false,
                "indexVersion" : 2,
                "direction" : "forward",
                "indexBounds" : {
                    "timestamp" : [ 
                        "(1501548359000.0, inf.0]"
                    ]
                }
            }
        }
    ]
},
"executionStats" : {
    "executionSuccess" : true,
    "nReturned" : 43,
    "executionTimeMillis" : 1512,
    "totalKeysExamined" : 221,
    "totalDocsExamined" : 219,
    "executionStages" : {
        "stage" : "FETCH",
        "filter" : {
            "timestamp" : {
                "$gt" : 1501548359000.0
            }
        },
        "nReturned" : 43,
        "executionTimeMillisEstimate" : 1431,
        "works" : 222,
        "advanced" : 43,
        "needTime" : 177,
        "needYield" : 0,
        "saveState" : 64,
        "restoreState" : 64,
        "isEOF" : 1,
        "invalidates" : 0,
        "docsExamined" : 219,
        "alreadyHasObj" : 0,
        "inputStage" : {
            "stage" : "IXSCAN",
            "nReturned" : 219,
            "executionTimeMillisEstimate" : 71,
            "works" : 221,
            "advanced" : 219,
            "needTime" : 1,
            "needYield" : 0,
            "saveState" : 64,
            "restoreState" : 64,
            "isEOF" : 1,
            "invalidates" : 0,
            "keyPattern" : {
                "rack_name" : 1
            },
            "indexName" : "rack",
            "isMultiKey" : false,
            "multiKeyPaths" : {
                "rack_name" : []
            },
            "isUnique" : false,
            "isSparse" : false,
            "isPartial" : false,
            "indexVersion" : 2,
            "direction" : "forward",
            "indexBounds" : {
                "rack_name" : [ 
                    "[\"helena2\", \"helena2\"]", 
                    "[\"providence1\", \"providence1\"]"
                ]
            },
            "keysExamined" : 221,
            "seeks" : 2,
            "dupsTested" : 0,
            "dupsDropped" : 0,
            "seenInvalidated" : 0
        }
    },
    "allPlansExecution" : [ 
        {
            "nReturned" : 2,
            "executionTimeMillisEstimate" : 31,
            "totalKeysExamined" : 221,
            "totalDocsExamined" : 221,
            "executionStages" : {
                "stage" : "FETCH",
                "filter" : {
                    "rack_name" : {
                        "$in" : [ 
                            "helena2", 
                            "providence1"
                        ]
                    }
                },
                "nReturned" : 2,
                "executionTimeMillisEstimate" : 31,
                "works" : 221,
                "advanced" : 2,
                "needTime" : 219,
                "needYield" : 0,
                "saveState" : 64,
                "restoreState" : 64,
                "isEOF" : 0,
                "invalidates" : 0,
                "docsExamined" : 221,
                "alreadyHasObj" : 0,
                "inputStage" : {
                    "stage" : "IXSCAN",
                    "nReturned" : 221,
                    "executionTimeMillisEstimate" : 10,
                    "works" : 221,
                    "advanced" : 221,
                    "needTime" : 0,
                    "needYield" : 0,
                    "saveState" : 64,
                    "restoreState" : 64,
                    "isEOF" : 0,
                    "invalidates" : 0,
                    "keyPattern" : {
                        "timestamp" : 1
                    },
                    "indexName" : "time",
                    "isMultiKey" : false,
                    "multiKeyPaths" : {
                        "timestamp" : []
                    },
                    "isUnique" : false,
                    "isSparse" : false,
                    "isPartial" : false,
                    "indexVersion" : 2,
                    "direction" : "forward",
                    "indexBounds" : {
                        "timestamp" : [ 
                            "(1501548359000.0, inf.0]"
                        ]
                    },
                    "keysExamined" : 221,
                    "seeks" : 1,
                    "dupsTested" : 0,
                    "dupsDropped" : 0,
                    "seenInvalidated" : 0
                }
            }
        }, 
        {
            "nReturned" : 43,
            "executionTimeMillisEstimate" : 1431,
            "totalKeysExamined" : 221,
            "totalDocsExamined" : 219,
            "executionStages" : {
                "stage" : "FETCH",
                "filter" : {
                    "timestamp" : {
                        "$gt" : 1501548359000.0
                    }
                },
                "nReturned" : 43,
                "executionTimeMillisEstimate" : 1431,
                "works" : 221,
                "advanced" : 43,
                "needTime" : 177,
                "needYield" : 0,
                "saveState" : 64,
                "restoreState" : 64,
                "isEOF" : 1,
                "invalidates" : 0,
                "docsExamined" : 219,
                "alreadyHasObj" : 0,
                "inputStage" : {
                    "stage" : "IXSCAN",
                    "nReturned" : 219,
                    "executionTimeMillisEstimate" : 71,
                    "works" : 221,
                    "advanced" : 219,
                    "needTime" : 1,
                    "needYield" : 0,
                    "saveState" : 64,
                    "restoreState" : 64,
                    "isEOF" : 1,
                    "invalidates" : 0,
                    "keyPattern" : {
                        "rack_name" : 1
                    },
                    "indexName" : "rack",
                    "isMultiKey" : false,
                    "multiKeyPaths" : {
                        "rack_name" : []
                    },
                    "isUnique" : false,
                    "isSparse" : false,
                    "isPartial" : false,
                    "indexVersion" : 2,
                    "direction" : "forward",
                    "indexBounds" : {
                        "rack_name" : [ 
                            "[\"helena2\", \"helena2\"]", 
                            "[\"providence1\", \"providence1\"]"
                        ]
                    },
                    "keysExamined" : 221,
                    "seeks" : 2,
                    "dupsTested" : 0,
                    "dupsDropped" : 0,
                    "seenInvalidated" : 0
                }
            }
        }
    ]
},
"serverInfo" : {
    "host" : "dtauto-sna01.mascorp.com",
    "port" : 27017,
    "version" : "3.4.4",
    "gitVersion" : "888390515874a9debd1b6c5d36559ca86b44babd"
},
"ok" : 1.0
}

我不明白的两件事:

  1. 当您查看AllPlansExecution时,nReturned密钥有所不同 每个计划的价值。第二个计划(指数:机架)实际上是赢家 计划并返回43个结果,这是实际的返回结果 整个查询,但第一个<{p>

  2. 的结果是nReturned
  3. 更多的挑战是为什么第一个计划(索引: 报告的时间是被拒绝的计划 executionTimeMillis价值31胜过赢家计划 executionTimeMillis 1431?

  4. 发生了什么?

1 个答案:

答案 0 :(得分:3)

allPlansExecution Mode文档页面对此进行了解释。换句话说:

  

MongoDB运行查询优化器以选择获胜计划并执行获胜计划以完成。在&#34; allPlansExecution&#34;模式,MongoDB返回描述获胜计划执行情况的统计数据,以及计划选择期间捕获的其他候选计划的统计数据。

在计划选择期间,如果有多个索引可以满足查询,MongoDB将使用所有有效计划运行试验,以确定哪个执行最佳。有关此流程的详细信息,请参阅Query Plans

从MongoDB 3.4.6开始,计划选择涉及在&#34; race&#34;中并行运行候选计划,并查看哪个候选计划首先返回101个结果。在上面的示例中,当获胜计划在比赛中返回101结果时,失败计划仅管理了2个结果。获胜计划然后执行完成。这就是失败计划仅在统计数据中显示nReturned: 2的原因。

这场&#34;比赛&#34;因为如果有两个相同的计划,由于JSON文档的灵活性,MongoDB不知道哪个计划对于特定查询是最佳的(与例如表格结构已知的SQL不同)。当然,MongoDB完全有可能猜错,并且最终得出一个不太高效的计划,因为它是一个经验过程。出于这个原因,最好创建支持您的查询的索引,以便MongoDB不必猜测。否则,您可以使用hint()告诉MongoDB使用哪个索引进行特定查询。

因此:

  • 获胜计划的统计信息是实际查询的结果统计信息。
  • 丢失计划的统计信息仅显示查询计划试运行的统计信息。
  • 计划选择包括参加比赛&#34;到101结果。只有当有多个索引可以满足查询时才会执行此竞争。

注1 :您看到的两个计划都不是很好。获胜计划会显示"nReturned" : 43"totalKeysExamined" : 221"totalDocsExamined" : 219。这意味着MongoDB需要检查219个文档才能返回其中43个:效率仅为20%。理想情况下,您希望nReturned数字等于totalDocsExamined

注意2 :尝试创建复合索引{'rack_name': 1, 'timestamp': 1}。使用相同的查询,您应该获得更好的效率数字。

注意3 :请注意,由于指定了allPlansExecution,所以MongoDB会为您提供所有统计信息以保证彻底性,但它与任何方面无关。最终的nReturned结果。这是一个被拒绝的计划,nReturned: 2号码可以令人困惑。如果您使用executionStats设置,则无法看到此统计信息。首先,allPlansExecution用于微调并确定为什么某些计划被拒绝。