gpt4 book ai didi

php - MongoDB:复合索引决策

转载 作者:可可西里 更新时间:2023-11-01 09:52:23 26 4
gpt4 key购买 nike

我最近不得不优化我们 MongoDB 上的某些查询集,并遇到了这个特殊问题:

假设我有一个匹配 AB 的查询,然后在 C 上进行范围选择,并通过在 上排序输出code>D,所以在 shell 中它们看起来像:

db.collection.find({ A: 'something', B: 'something-else', C: { $gt: 100 } })
.sort({ D: -1 }).limit(10)

read a post去年谈到为这种场景创建索引,他们的基本规则:

  1. 精确值匹配字段优先
  2. 排序字段次之
  3. 范围搜索($in、$gt 等)字段排在最后

他们的树解释看起来很合理,所以我继续创建了一个索引:

db.collection.ensureIndex({ A:1, B:1, D:-1, C:-1 })

现在问题来了:mongodb 认为 BasicCursor 比这个索引更好。如果我提示完整的索引,它就可以工作(而且速度更快),但这样做需要对我们的代码库进行相当多的更改,因此我们正在尽可能避免这种情况。


我的问题是:

  1. 为什么 mongodb 查询优化器决定 { A:1, E:-1 }, { D:-1 } 甚至 BasicCursor 比 { A:1, B:1, D:-1, C:-1 },当我的查询包含所有 4 个字段时。

  2. { A:1, D:-1 } 是否冗余,mongo docs是否说使用部分索引效率较低?

此外,我们还有如下查询:

db.collection.find({ A: { $in : ['str1','str2'] }, B: 'something', C: { $gt: 100 } })
.sort({ D: -1 }).limit(10)

为了高效查询,我们是否需要像下面这样的额外索引?坦率地说,我不确定 MongoDB 查询优化器将如何处理它们。

db.collection.ensureIndex({ B:1, D:-1, C:-1, A:1 })

这些是我的查询的解释,有提示和没有提示。

原来它默认为 { A:1, E:-1 } 而不是 { A:1, D:-1 } ,这看起来更奇怪我们没有查询字段 E。

我在 { A:1, E:-1 } 上删除了索引,现在解释告诉我它默认为 { D:-1 },所以我删除了它也是,现在 MongoDB 开始使用 BasicCursor... 它似乎既不喜欢我的完整索引也不喜欢 A:1, D:-1 索引(尽管提示会带来更好的性能)。

这感觉很奇怪。

最佳答案

发生这种“不寻常”的唯一原因是,如果您的数据分布恰好是 BasicCursor 实际上比索引查询更快地完成查询(即找到所有匹配的文档)。 “部分”索引也是如此。

以您的数据结构为例,如果 a 在集合的开头具有相对较少的不同值,并且 b 具有极低的基数(即非常少的不同值,例如 one 或 a少数)然后按顺序扫描集合或使用“效率较低”的索引将显示与使用理论上的“理想”索引相同或更好的性能。

这是一个示例,其中前 1000 个文档具有 a=1 和 b=2 - 后面的文档分布非常不同。

> db.compound4.find({a:1, b:2, d:{$lt:100}}).sort({c:-1}).limit(10).explain(true)
{
"cursor" : "BtreeCursor a_1",
"isMultiKey" : false,
"n" : 10,
"nscannedObjects" : 18,
"nscanned" : 18,
"nscannedObjectsAllPlans" : 46,
"nscannedAllPlans" : 56,
"scanAndOrder" : true,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
"a" : [
[
1,
1
]
]
},
"allPlans" : [
{
"cursor" : "BtreeCursor a_1",
"n" : 18,
"nscannedObjects" : 18,
"nscanned" : 18,
"indexBounds" : {
"a" : [
[
1,
1
]
]
}
},
{
"cursor" : "BtreeCursor a_1_b_1_c_1_d_1 reverse",
"n" : 10,
"nscannedObjects" : 10,
"nscanned" : 20,
"indexBounds" : {
"a" : [
[
1,
1
]
],
"b" : [
[
2,
2
]
],
"c" : [
[
{
"$maxElement" : 1
},
{
"$minElement" : 1
}
]
],
"d" : [
[
100,
-1.7976931348623157e+308
]
]
}
},
{
"cursor" : "BasicCursor",
"n" : 18,
"nscannedObjects" : 18,
"nscanned" : 18,
"indexBounds" : {

}
}
]
}

由于复合索引很大,它比较小的部分索引需要更长的时间来遍历,并且由于“b”的选择性不是很好(即非常差),这使得查询计划落后。

关于php - MongoDB:复合索引决策,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20828977/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com