需要帮助了解界限

我们最近决定重新访问一些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
            ]
        ]
    }
}

我们错过了一些多键索引的基础知识,或者我们正面临一个错误。

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

  • https://groups.google.com/forum/#!searchin/mongodb-user/multikey$20bounds/mongodb-user/RKrsyzRwHrE/_i0SxdJV5qcJ
  • MongoDB范围查询中$ lt和$ gt的顺序
  • 不幸的是,这些帖子解决了在多键值上设置范围的不同用例。

    我们试过的其他事情:

  • 更改复合索引排序,从非multikey字段开始。

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

  • 定义范围时使用$和operator:

    db.demo.find({'attr.name': 'c', $and: [{num: {$lt: 3}}, {num: {$gt: 1}}]})
    
  • 使用MongoDB v2.5.4

  • 以上都没有任何效果(第2.5.4节通过完全抛弃范围的两端使事情变得更糟)。

    任何形式的帮助将不胜感激!

    非常感谢,

    投资回报率


    对于其中一个索引字段是数组的复合索引,MongoDB将只使用范围查询的下限或上限来确保返回正确的匹配。 请参阅SERVER-958,其中约束到上下两个索引边界将找不到预期的文档。

    如果您的范围查询位于数组字段上,则可以使用$elemMatch运算符在预期的索引范围内优化您的查询。 和在MongoDB 2.4中一样, $elemMatch操作符在非数组字段上不起作用,所以不幸的是这对你的用例没有帮助。 您可以观看/向上投票SERVER-6050:考虑允许将$ elemMatch应用于MongoDB问题跟踪器中的非数组。

    还有一个未解决的问题SERVER-7959:当某些字段是多键描述此行为时,可能会有带有复合索引的意外扫描。


    $ min和$ max操作符可以帮助您解决此问题,方法是允许您显式指定索引边界。

    例:

    db.demo.find({foo: {$lt:3, $gt: 1}, 'attr.name': 'c'}).
     hint('attr.name_1_foo_1').
     min({'attr.name': 'c', foo: 1.000001}).
     max({'attr.name': 'c', foo: 3}).explain()
    

    结果:

    {
        "cursor" : "BtreeCursor attr.name_1_foo_1",
        "isMultiKey" : true,
        "n" : 1,
        "nscannedObjects" : 1,
        "nscanned" : 1,
        "nscannedObjectsAllPlans" : 1,
        "nscannedAllPlans" : 1,
        "scanAndOrder" : false,
        "indexOnly" : false,
        "nYields" : 0,
        "nChunkSkips" : 0,
        "millis" : 0,
        "indexBounds" : {
            "start" : {
                "attr.name" : "c",
                "foo" : 1.000001
            },
            "end" : {
                "attr.name" : "c",
                "foo" : 3
            }
        }
    }
    

    但有一些重要的警告:

  • $ min始终包含(如$ gte),$ max始终是独占的(如$ lt)。 您可能需要调整您的值以获得$ gt或$ lte的效果。
  • $ min和$ max中的字段必须与索引中的字段完全匹配。
  • 每个查询只能有一组索引边界。 对于$ in或$或query,没有等价物。
  • 虽然操作员被记录在案,但似乎并未建议在正常使用情况下使用。
  • 第3点对我来说是一个阻碍(我需要在数组字段中做一个$ in),所以我仍然在寻找另一个解决方案。

    来源:https://groups.google.com/forum/#!msg/mongodb-user/oxL8wuVdITA/uWJHVbMd_-8J

    链接地址: http://www.djcxy.com/p/57911.html

    上一篇: Need Help Understanding Bounds

    下一篇: Query for documents where array size is greater than 1