MongoDB Multikey复合索引 - 需要帮助了解边界

 会展小控 发布于 2023-02-08 12:21

我们最近决定重新访问一些MongoDB索引,并在使用包含多键部分的复合索引时遇到了一个奇怪的结果.

值得注意的是,我们正在使用v2.4.5

TLDR:当使用具有多键部分的复合索引时,删除用于范围限制的非多键字段的边界.

我将用一个例子来解释这个问题:

创建一些数据

db.demo.insert(
[{ "foo" : 1, "attr" : [  {  "name" : "a" },  {  "name" : "b" },  {  "name" : "c" } ]},
 { "foo" : 2, "attr" : [  {  "name" : "b" },  {  "name" : "c" },  {  "name" : "d" } ]},
 { "foo" : 3, "attr" : [  {  "name" : "c" },  {  "name" : "d" },  {  "name" : "e" } ]},
 { "foo" : 4, "attr" : [  {  "name" : "d" },  {  "name" : "e" },  {  "name" : "f" } ]}])

指数

db.demo.ensureIndex({'attr.name': 1, 'foo': 1})

查询和解释

查询'attr.name'但约束非多键字段'foo'的范围:

db.demo.find({foo: {$lt:3, $gt: 1}, 'attr.name': 'c'}).hint('attr.name_1_foo_1').explain()
{
    "cursor" : "BtreeCursor attr.name_1_foo_1",
    "isMultiKey" : true,
    "n" : 1,
    "nscannedObjects" : 2,
    "nscanned" : 2,
    "nscannedObjectsAllPlans" : 2,
    "nscannedAllPlans" : 2,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 0,
    "nChunkSkips" : 0,
    "millis" : 0,
    "indexBounds" : {
        "attr.name" : [
            [
                "c",
                "c"
            ]
        ],
        "foo" : [
            [
                -1.7976931348623157e+308,
                3
            ]
        ]
    }
}

正如您所看到的,'foo'的范围不是在查询中定义的,一端被完全忽略,这导致nscanned比它应该更大.

更改范围操作数的顺序将改变删除的结尾:

db.demo.find({foo: {$gt: 1, $lt:3}, 'attr.name': 'c'}).hint('attr.name_1_foo_1').explain()
{
    "cursor" : "BtreeCursor attr.name_1_foo_1",
    "isMultiKey" : true,
    "n" : 1,
    "nscannedObjects" : 2,
    "nscanned" : 2,
    "nscannedObjectsAllPlans" : 2,
    "nscannedAllPlans" : 2,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 0,
    "nChunkSkips" : 0,
    "millis" : 0,
    "indexBounds" : {
        "attr.name" : [
            [
                "c",
                "c"
            ]
        ],
        "foo" : [
            [
                1,
                1.7976931348623157e+308
            ]
        ]
    }
}

我们要么错过了一些多键索引基础知识,要么就是我们遇到了一个bug.

我们经历过类似的话题,包括:

https://groups.google.com/forum/#!searchin/mongodb-user/multikey$20bounds/mongodb-user/RKrsyzRwHrE/_i0SxdJV5qcJ

MongoDB范围查询中$ lt和$ gt的顺序

不幸的是,这些帖子解决了一个不同的用例,其中在多键值上设置了范围.

我们尝试过的其他事情:

更改复合索引排序,从非多键字段开始.

将'foo'值放在'attr'数组的每个子文档中,索引('attr.name','attr.foo')并在'attr'上执行$ elemMatch,并在'foo'上设置范围约束.

定义范围时使用$和运算符:

db.demo.find({'attr.name': 'c', $and: [{num: {$lt: 3}}, {num: {$gt: 1}}]})

使用MongoDB v2.5.4

以上都没有任何影响(v2.5.4通过完全倾倒范围的两端使事情变得更糟).

任何形式的帮助将非常感谢!

非常感谢,

投资回报率

撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有