【发布时间】:2015-05-06 03:21:24
【问题描述】:
我们最近决定重新审视我们的一些 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
- Order of $lt and $gt in MongoDB range query
不幸的是,这些帖子解决了在多键值上设置范围的不同用例。
我们尝试做的其他事情:
更改复合索引顺序,从非多键字段开始。
将 'foo' 值放入 'attr' 数组中的每个子文档中,按 ('attr.name', 'attr.foo') 索引并在 'attr' 上执行 $elemMatch 'foo' 的范围限制。
-
在定义范围时使用 $and 运算符:
db.demo.find({'attr.name': 'c', $and: [{num: {$lt: 3}}, {num: {$gt: 1}}]}) 使用 MongoDB v2.5.4
以上都没有任何影响(v2.5.4 通过完全倾倒范围的两端使事情变得更糟)。
我们将不胜感激任何形式的帮助!
非常感谢,
投资回报率
【问题讨论】:
标签: mongodb