【问题标题】:Mongodb Index not used in case of $or query在 $or 查询的情况下不使用 Mongodb 索引
【发布时间】:2019-08-23 06:55:34
【问题描述】:

我已添加创建集合first 并创建索引;

db.first.createIndex({a:1, b:1, c:1, d:1, e:1, f:1});

然后插入数据

db.first.insert({a:1, b:2, c:3, d:4, e:5, f:6});
db.first.insert({a:1, b:6});

当进行类似查询时

db.first.find({f: 6, a:1, c:3}).sort({b: -1}).explain();

使用索引 (IXSCAN)

{
    "queryPlanner" : {
        "plannerVersion" : 1,
        "namespace" : "myproject.first",
        "indexFilterSet" : false,
        "parsedQuery" : {
            "$and" : [
                {
                    "a" : {
                        "$eq" : 1
                    }
                },
                {
                    "c" : {
                        "$eq" : 3
                    }
                },
                {
                    "f" : {
                        "$eq" : 6
                    }
                }
            ]
        },
        "winningPlan" : {
            "stage" : "FETCH",
            "inputStage" : {
                "stage" : "IXSCAN",
                "keyPattern" : {
                    "a" : 1,
                    "b" : 1,
                    "c" : 1,
                    "d" : 1,
                    "e" : 1,
                    "f" : 1
                },
                "indexName" : "a_1_b_1_c_1_d_1_e_1_f_1",
                "isMultiKey" : false,
                "multiKeyPaths" : {
                    "a" : [ ],
                    "b" : [ ],
                    "c" : [ ],
                    "d" : [ ],
                    "e" : [ ],
                    "f" : [ ]
                },
                "isUnique" : false,
                "isSparse" : false,
                "isPartial" : false,
                "indexVersion" : 2,
                "direction" : "backward",
                "indexBounds" : {
                    "a" : [
                        "[1.0, 1.0]"
                    ],
                    "b" : [
                        "[MaxKey, MinKey]"
                    ],
                    "c" : [
                        "[3.0, 3.0]"
                    ],
                    "d" : [
                        "[MaxKey, MinKey]"
                    ],
                    "e" : [
                        "[MaxKey, MinKey]"
                    ],
                    "f" : [
                        "[6.0, 6.0]"
                    ]
                }
            }
        },
        "rejectedPlans" : [
            {
                "stage" : "SORT",
                "sortPattern" : {
                    "b" : -1
                },
                "inputStage" : {
                    "stage" : "SORT_KEY_GENERATOR",
                    "inputStage" : {
                        "stage" : "FETCH",
                        "filter" : {
                            "$and" : [
                                {
                                    "c" : {
                                        "$eq" : 3
                                    }
                                },
                                {
                                    "f" : {
                                        "$eq" : 6
                                    }
                                }
                            ]
                        },
                        "inputStage" : {
                            "stage" : "IXSCAN",
                            "keyPattern" : {
                                "a" : 1
                            },
                            "indexName" : "a_1",
                            "isMultiKey" : false,
                            "multiKeyPaths" : {
                                "a" : [ ]
                            },
                            "isUnique" : false,
                            "isSparse" : false,
                            "isPartial" : false,
                            "indexVersion" : 2,
                            "direction" : "forward",
                            "indexBounds" : {
                                "a" : [
                                    "[1.0, 1.0]"
                                ]
                            }
                        }
                    }
                }
            }
        ]
    },
    "serverInfo" : {
        "host" : "Manishs-MacBook-Pro.local",
        "port" : 27017,
        "version" : "3.6.4",
        "gitVersion" : "d0181a711f7e7f39e60b5aeb1dc7097bf6ae5856"
    },
    "ok" : 1
}

但是当我使用或查询时

db.first.find({ $or: [{f: 6}, {a:1}]}).explain();

不使用索引,而是扫描列 (COLLSCAN)

{
    "queryPlanner" : {
        "plannerVersion" : 1,
        "namespace" : "myproject.first",
        "indexFilterSet" : false,
        "parsedQuery" : {
            "$or" : [
                {
                    "a" : {
                        "$eq" : 1
                    }
                },
                {
                    "f" : {
                        "$eq" : 6
                    }
                }
            ]
        },
        "winningPlan" : {
            "stage" : "SUBPLAN",
            "inputStage" : {
                "stage" : "COLLSCAN",
                "filter" : {
                    "$or" : [
                        {
                            "a" : {
                                "$eq" : 1
                            }
                        },
                        {
                            "f" : {
                                "$eq" : 6
                            }
                        }
                    ]
                },
                "direction" : "forward"
            }
        },
        "rejectedPlans" : [ ]
    },
    "serverInfo" : {
        "host" : "Manishs-MacBook-Pro.local",
        "port" : 27017,
        "version" : "3.6.4",
        "gitVersion" : "d0181a711f7e7f39e60b5aeb1dc7097bf6ae5856"
    },
    "ok" : 1
}

如果我做错了什么,请告诉我。

【问题讨论】:

    标签: database mongodb indexing


    【解决方案1】:

    您拥有复合索引的事实是索引未与$or 一起使用的原因。

    当评估 $or 表达式中的子句时,MongoDB 要么 执行集合扫描,或者,如果所有子句都支持 索引,MongoDB 执行索引扫描。也就是说,对于 MongoDB 使用 用于评估 $or 表达式的索引,$or 中的所有子句 表达式必须由索引支持。否则,MongoDB 将 执行集合扫描。

    当使用带有 $or 查询的索引时,$or 的每个子句都可以使用它的 自己的索引。考虑以下查询:

    db.inventory.find( { $or: [ { quantity: { $lt: 20 } }, { price: 10 } ] } )
    

    要支持此查询,而不是复合索引,您可以创建 一个数量指标和另一个价格指标:

    db.inventory.createIndex( { quantity: 1 } )
    db.inventory.createIndex( { price: 1 } )
    

    $or Clauses and Indexes


    因此,只需为字段 fa 添加单独的索引即可;

    db.first.createIndex({a:1});
    db.first.createIndex({f:1});
    

    会让你的

    db.first.find({ $or: [{f: 6}, {a:1}]})
    

    查询以使用索引。

    【讨论】:

    • 感谢您的快速响应。或查询在键 fa 上,这两个键都在索引 {a:1, b:2, c:3, d:4, e:5, f:6} 中,为什么它仍然不使用索引?
    • @FastTurtle 因为它是一个复合索引,并且对于使用索引的$or 操作,它需要目标字段上的单独索引,因为每个索引都应该独立于其他字段进行评估。检查我更新的答案,看看我最后建议的createIndex 电话
    【解决方案2】:

    这里的问题是,您在 {a:1, b:1, c:1, d:1, e:1, f:1} 字段上创建了复合索引,但您没有遵循顺序的指数。因此,您的查询应该包含与您构建索引的顺序相同的所有字段。由于字段“f”位于索引的尾部,您的查询将不会利用甚至识别它

    您的查询:

    db.first.find({f: 6, a:1, c:3}).sort({b: -1})
    db.first.find({ $or: [{f: 6}, {a:1}]})
    

    要使上述两个查询都使用索引,您应该如下构建复合索引:

    db.first.createIndex({ f:1, a:1, b:1, c:1 })
    

    或者:您可以在所有字段上建立单独的索引,并在查询中以任何顺序使用它。

    记住:如果你正在构建复合索引,请确保遵循平等、排序和范围顺序

    【讨论】:

    • 任何原因 db.first.find({f: 6, a:1, c:3}).sort({b: -1}) 命中索引但未命中索引 db.first.find({ $or: [{f: 6}, {a:1}]})
    • 因为您的第二个查询使用 $or 运算符,它必须在字段上具有单独的索引,或者您以正确的顺序构建复合索引
    猜你喜欢
    • 1970-01-01
    • 2022-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-28
    • 1970-01-01
    • 1970-01-01
    • 2010-12-06
    相关资源
    最近更新 更多