这是一个关于如何在查询具有“或”时创建高效索引的问题。没有“或”,我知道如何创建有效的索引。
这是我的疑问。
db.collection.find({
'msg.sendTime':{$gt:1},
'msg.msgType':{$in:["chat","g_card"]},
$or:[{'msg.recvId':{$in:['xm80049258']}},{'msg.userId':'xm80049258'}],
$orderby:{'msg.sendTime':-1}})
阅读完一篇文章后,我在msg.recvId和msg.userId上创建了两个单一的索引,这很有意义。
我想知道mongodb何时执行“或”,它是否首先分割所有文件,然后使用msg.sendTime和msg.msgType?
如何在这种情况下创建高效索引?我应该创建索引(msg.sendTime:1,msg.msgType:1,msg.recvId:1)和 (msg.sendTime:1,msg.msgType:1,msg.userId:1)
非常感谢。
答案 0 :(得分:0)
在评估$或表达式中的子句时,MongoDB执行集合扫描,或者如果索引支持所有子句,MongoDB将执行索引扫描。也就是说,对于MongoDB使用索引来计算$或表达式,$或表达式中的所有子句必须由索引支持。
同样来自Indexing Strategies:
通常,MongoDB只使用一个索引来完成大多数查询。但是,$或查询的每个子句都可以使用不同的索引
这些段落对$or
查询的意思是:
find()
查询中,只能使用一个索引。因此,最好创建一个与查询中的字段对齐的索引。否则,MongoDB将进行集合扫描。$or
查询之外,MongoDB可以使用每$or
个字词的 $or
,最好将$or
字词作为顶级字词,并为每个字词创建一个索引分别强> 所以回答你的问题:
我想知道mongodb何时执行"或",它是否首先划分所有文档,然后使用msg.sendTime和msg.msgType?
如果您的查询具有顶级$or
子句,MongoDB可以使用每个子句一个索引。否则,它将执行集合扫描或半集合扫描。例如,如果您有索引:
db.collection.createIndex({a: 1, b: 1})
您可以创建两种常规类型的查询:
$or
不在查询的顶层此查询可以使用索引,但不具备性能:
db.collection.find({a: 1, $or: [{b: 1}, {b: 2}]})
因为查询的explain()
输出是:
> db.collection.explain().find({a: 1, $or: [{b: 1}, {b: 2}]})
{
"queryPlanner": {
...
"indexBounds": {
"a": [
"[1.0, 1.0]"
],
"b": [
"[MinKey, MaxKey]"
]
...
请注意,查询计划程序无法使用b
字段的正确边界,因为它正在进行半集合扫描(因为它正在从{{1}搜索b
到MinKey
,即一切)。上面的查询规划器结果基本上是说:"查找MaxKey
的文档,并扫描a = 1
的所有文件,其值为b
或1
" 强>
2
但是,将$or
子句拉到顶层:
$or
将导致此查询计划:
db.collection.find({$or: [{a: 1, b: 1}, {a: 1, b: 2}]})
请注意,> db.test.explain().find({$or: [{a: 1, b: 1}, {a: 1, b: 2}]})
{
"queryPlanner": {
...
"winningPlan": {
"stage": "SUBPLAN",
...
"inputStages": [
{
"stage": "IXSCAN",
...
"indexBounds": {
"a": [
"[1.0, 1.0]"
],
"b": [
"[1.0, 1.0]"
]
}
},
{
"stage": "IXSCAN",
...
"indexBounds": {
"a": [
"[1.0, 1.0]"
],
"b": [
"[2.0, 2.0]"
]
的每个术语都被视为一个单独的查询,每个查询都有一个紧密的边界。因此,上面的查询计划是:"查找$or
或a = 1, b = 1
" 的文档。可以想象,与先前的查询相比,此查询将更加高效。
关于你的第二个问题:
在这种情况下如何创建高效索引?我应该创建索引(msg.sendTime:1,msg.msgType:1,msg.recvId:1)和(msg.sendTime:1,msg.msgType:1,msg.userId:1)
如上所述,您需要将正确的查询与适当的索引相结合,以获得最佳结果。您建议的两个索引将能够被MongoDB使用,并且如果您重新排列查询以在查询的顶级中包含a = 1, b = 2
,那么这些索引将最有效。
我建议您了解MongoDB的$or
输出,因为它是确定您的查询是否使用正确索引的最佳工具。
您可能会发现有用的相关资源是: