为什么MongoDB的查询计划程序不喜欢部分索引?

时间:2019-09-21 21:59:44

标签: mongodb indexing

对于此查询:

db.MyCollection.explain("allPlansExecution").find({
    myId: "abc123",
    myBoolean: false
}).sort({
    myDate: -1
}).skip(0).limit(50)

有两种选择:

indexA: { myId: 1, myDate: 1 }
indexB: { myId: 1, myDate: -1 }, { partialFilterExpression: { myBoolean: false }}

查询计划者选择indexA而不是indexB,即使:

  • indexB的索引存储大小大约减小30%(占用更少的RAM)
  • myBoolean中的部分过滤器已经满足indexB查询限制
  • indexA的排序方向与查询不符,而indexB的排序方向是正确的

queryPlanner

"queryPlanner" : {
    "plannerVersion" : 1,
    "namespace" : "myDb.MyCollection",
    "indexFilterSet" : false,
    "parsedQuery" : {
        "$and" : [
            {
                "myId" : {
                    "$eq" : "abc123"
                }
            },
            {
                "myBoolean" : {
                    "$eq" : false
                }
            }
        ]
    },
    "winningPlan" : {
        "stage" : "LIMIT",
        "limitAmount" : 50,
        "inputStage" : {
            "stage" : "FETCH",
            "filter" : {
                "myBoolean" : {
                    "$eq" : false
                }
            },
            "inputStage" : {
                "stage" : "IXSCAN",
                "keyPattern" : {
                    "myId" : 1,
                    "myDate" : 1
                },
                "indexName" : "indexA",
                "isMultiKey" : false,
                "multiKeyPaths" : {
                    "myId" : [ ],
                    "myDate" : [ ]
                },
                "isUnique" : false,
                "isSparse" : false,
                "isPartial" : false,
                "indexVersion" : 2,
                "direction" : "backward",
                "indexBounds" : {
                    "myId" : [
                        "[\"abc123\", \"abc123\"]"
                    ],
                    "myDate" : [
                        "[MaxKey, MinKey]"
                    ]
                }
            }
        }
    },
    "rejectedPlans" : [
        {
            "stage" : "LIMIT",
            "limitAmount" : 50,
            "inputStage" : {
                "stage" : "FETCH",
                "filter" : {
                    "myBoolean" : {
                        "$eq" : false
                    }
                },
                "inputStage" : {
                    "stage" : "IXSCAN",
                    "keyPattern" : {
                        "myId" : 1,
                        "myDate" : -1
                    },
                    "indexName" : "indexB",
                    "isMultiKey" : false,
                    "multiKeyPaths" : {
                        "myId" : [ ],
                        "myDate" : [ ]
                    },
                    "isUnique" : false,
                    "isSparse" : false,
                    "isPartial" : true,
                    "indexVersion" : 2,
                    "direction" : "forward",
                    "indexBounds" : {
                        "myId" : [
                            "[\"abc123\", \"abc123\"]"
                        ],
                        "myDate" : [
                            "[MaxKey, MinKey]"
                        ]
                    }
                }
            }
        }
    ]
}

我在plan ranker中找不到答案。

查询计划(有趣的是indexB没有分数):

{
    "plans" : [
        {
            "details" : {
                "solution" : "(index-tagged expression tree: tree=Node\n---Leaf indexA, pos: 0, can combine? 1\n---Leaf \n)"
            },
            "reason" : {
                "score" : 1.233944859813084,
                "stats" : {
                    "stage" : "LIMIT",
                    "nReturned" : 50,
                    "executionTimeMillisEstimate" : 0,
                    "works" : 214,
                    "advanced" : 50,
                    "needTime" : 164,
                    "needYield" : 0,
                    "saveState" : 3,
                    "restoreState" : 3,
                    "isEOF" : 1,
                    "invalidates" : 0,
                    "limitAmount" : 50,
                    "inputStage" : {
                        "stage" : "SKIP",
                        "nReturned" : 50,
                        "executionTimeMillisEstimate" : 0,
                        "works" : 214,
                        "advanced" : 50,
                        "needTime" : 164,
                        "needYield" : 0,
                        "saveState" : 3,
                        "restoreState" : 3,
                        "isEOF" : 0,
                        "invalidates" : 0,
                        "skipAmount" : 0,
                        "inputStage" : {
                            "stage" : "FETCH",
                            "filter" : {
                                "myBoolean" : {
                                    "$eq" : false
                                }
                            },
                            "nReturned" : 214,
                            "executionTimeMillisEstimate" : 0,
                            "works" : 214,
                            "advanced" : 214,
                            "needTime" : 0,
                            "needYield" : 0,
                            "saveState" : 3,
                            "restoreState" : 3,
                            "isEOF" : 0,
                            "invalidates" : 0,
                            "docsExamined" : 214,
                            "alreadyHasObj" : 0,
                            "inputStage" : {
                                "stage" : "IXSCAN",
                                "nReturned" : 214,
                                "executionTimeMillisEstimate" : 0,
                                "works" : 214,
                                "advanced" : 214,
                                "needTime" : 0,
                                "needYield" : 0,
                                "saveState" : 3,
                                "restoreState" : 3,
                                "isEOF" : 0,
                                "invalidates" : 0,
                                "keyPattern" : {
                                    "myId" : 1,
                                    "myDate" : 1
                                },
                                "indexName" : "indexA",
                                "isMultiKey" : false,
                                "multiKeyPaths" : {
                                    "myId" : [ ],
                                    "myDate" : [ ]
                                },
                                "isUnique" : false,
                                "isSparse" : false,
                                "isPartial" : false,
                                "indexVersion" : 2,
                                "direction" : "backward",
                                "indexBounds" : {
                                    "myId" : [
                                        "[\"abc123\", \"abc123\"]"
                                    ],
                                    "myDate" : [
                                        "[MaxKey, MinKey]"
                                    ]
                                },
                                "keysExamined" : 214,
                                "seeks" : 1,
                                "dupsTested" : 0,
                                "dupsDropped" : 0,
                                "seenInvalidated" : 0
                            }
                        }
                    }
                }
            },
            "feedback" : {
                "nfeedback" : 20,
                "scores" : [
                    {
                        "score" : 2.0003
                    },
                    {
                        "score" : 1.0003
                    },
                    {
                        "score" : 1.9586333333333334
                    },
                    {
                        "score" : 1.0003
                    },
                    {
                        "score" : 2.0003
                    },
                    {
                        "score" : 1.0003
                    },
                    {
                        "score" : 1.0003
                    },
                    {
                        "score" : 1.9806921568627451
                    },
                    {
                        "score" : 1.0003
                    },
                    {
                        "score" : 1.9806921568627451
                    },
                    {
                        "score" : 1.1896939393939394
                    },
                    {
                        "score" : 1.9503
                    },
                    {
                        "score" : 1.1669666666666667
                    },
                    {
                        "score" : 1.0003
                    },
                    {
                        "score" : 2.0003
                    },
                    {
                        "score" : 1.0003
                    },
                    {
                        "score" : 1.8003
                    },
                    {
                        "score" : 2.0003
                    },
                    {
                        "score" : 2.0003
                    },
                    {
                        "score" : 1.0003
                    }
                ]
            },
            "filterSet" : false
        },
        {
            "details" : {
                "solution" : "(index-tagged expression tree: tree=Node\n---Leaf indexB, pos: 0, can combine? 1\n---Leaf \n)"
            },
            "reason" : {
                "score" : 1.233944859813084,
                "stats" : {
                    "stage" : "LIMIT",
                    "nReturned" : 50,
                    "executionTimeMillisEstimate" : 0,
                    "works" : 214,
                    "advanced" : 50,
                    "needTime" : 164,
                    "needYield" : 0,
                    "saveState" : 3,
                    "restoreState" : 3,
                    "isEOF" : 1,
                    "invalidates" : 0,
                    "limitAmount" : 50,
                    "inputStage" : {
                        "stage" : "SKIP",
                        "nReturned" : 50,
                        "executionTimeMillisEstimate" : 0,
                        "works" : 214,
                        "advanced" : 50,
                        "needTime" : 164,
                        "needYield" : 0,
                        "saveState" : 3,
                        "restoreState" : 3,
                        "isEOF" : 0,
                        "invalidates" : 0,
                        "skipAmount" : 0,
                        "inputStage" : {
                            "stage" : "FETCH",
                            "filter" : {
                                "myBoolean" : {
                                    "$eq" : false
                                }
                            },
                            "nReturned" : 214,
                            "executionTimeMillisEstimate" : 0,
                            "works" : 214,
                            "advanced" : 214,
                            "needTime" : 0,
                            "needYield" : 0,
                            "saveState" : 3,
                            "restoreState" : 3,
                            "isEOF" : 0,
                            "invalidates" : 0,
                            "docsExamined" : 214,
                            "alreadyHasObj" : 0,
                            "inputStage" : {
                                "stage" : "IXSCAN",
                                "nReturned" : 214,
                                "executionTimeMillisEstimate" : 0,
                                "works" : 214,
                                "advanced" : 214,
                                "needTime" : 0,
                                "needYield" : 0,
                                "saveState" : 3,
                                "restoreState" : 3,
                                "isEOF" : 0,
                                "invalidates" : 0,
                                "keyPattern" : {
                                    "myId" : 1,
                                    "myDate" : -1
                                },
                                "indexName" : "indexB",
                                "isMultiKey" : false,
                                "multiKeyPaths" : {
                                    "myId" : [ ],
                                    "myDate" : [ ]
                                },
                                "isUnique" : false,
                                "isSparse" : false,
                                "isPartial" : true,
                                "indexVersion" : 2,
                                "direction" : "forward",
                                "indexBounds" : {
                                    "myId" : [
                                        "[\"abc123\", \"abc123\"]"
                                    ],
                                    "myDate" : [
                                        "[MaxKey, MinKey]"
                                    ]
                                },
                                "keysExamined" : 214,
                                "seeks" : 1,
                                "dupsTested" : 0,
                                "dupsDropped" : 0,
                                "seenInvalidated" : 0
                            }
                        }
                    }
                }
            },
            "feedback" : {

            },
            "filterSet" : false
        }
    ],
    "timeOfCreation" : ISODate("2019-09-21T18:26:02.108Z"),
    "ok" : 1,
    "operationTime" : Timestamp(1569105839, 834),
    "$clusterTime" : {
        "clusterTime" : Timestamp(1569105839, 834),
        "signature" : {...}
    }
}
  • indexB为什么不赢?
  • 为什么feedback没有scoresindexB
  • 为什么两个索引的总索引得分(1.233944859813084)相同?

0 个答案:

没有答案