这个问题让我发疯了。我有一个集合:
var ethTransactionSchema = new mongoose.Schema({
blockNumber: Number,
blockHash: String,
hash: String,
transactionIndex: Number,
from: String,
to: String,
value: String
});
ethTransactionSchema.index({ hash: 1 }, { unique: true });
ethTransactionSchema.index({ from: 1 });
ethTransactionSchema.index({ to: 1 });
ethTransactionSchema.index({ blockNumber: 1, transactionIndex: 1 });
ethTransactionSchema.index({ from: 1, to: 1, blockNumber: 1, transactionIndex: 1 });
ethTransactionSchema.index({ from: 1, blockNumber: 1, transactionIndex: 1});
ethTransactionSchema.index({ to: 1, blockNumber: 1, transactionIndex: 1 });
ethTransactionSchema.index({ to: 1, blockNumber: 1 });
ethTransactionSchema.index({ from: 1, blockNumber: 1 });
ethTransactionSchema.index({ from: 1, to: 1, blockNumber: 1 });
ethTransactionSchema.index({ blockNumber: 1 });
ethTransactionSchema.index({ transactionIndex: 1 });
ethTransactionSchema.index({ blockNumber: -1 });
ethTransactionSchema.index({ to: 1, blockNumber: -1 });
ethTransactionSchema.index({ from: 1, blockNumber: -1 });
ethTransactionSchema.index({ from: 1, to: 1, blockNumber: -1 });
ethTransactionSchema.index({ from: 1, to: 1, blockNumber: -1, transactionIndex: -1 });
ethTransactionSchema.index({ from: 1, blockNumber: -1, transactionIndex: -1 });
ethTransactionSchema.index({ to: 1, blockNumber: -1, transactionIndex: -1 });
执行此查询时:
find({"$and":[ {"$or": [ {"from":"0x120a270bbc009644e35f0bb6ab13f95b8199c4ad"},
{"to":"0x120a270bbc009644e35f0bb6ab13f95b8199c4ad"}
]},
{"blockNumber":{"$gte":1289597}}
]
}).sort({ blockNumber: -1, transactionIndex: -1 })
使用lte:
的同一查询需要3到6倍 find({"$and":[ {"$or": [ {"from":"0x120a270bbc009644e35f0bb6ab13f95b8199c4ad"},
{"to":"0x120a270bbc009644e35f0bb6ab13f95b8199c4ad"}
]},
{"blockNumber":{"$lte":1289597}}
]
}).sort({ blockNumber: -1, transactionIndex: -1 })
你可以看到我尝试了很多索引组合只是为了测试我是否可以使用frute force解决问题,但我可能会遗漏一些东西。我出于这个原因即将放弃MongoDB。 快速查询需要56毫秒,缓慢的167毫秒平均值。
有人可以找出问题的原因或帮助我找到它吗?
答案 0 :(得分:4)
您尝试做的事情存在一些问题:
$or
查询使用不同的索引
要使$or
个查询能够使用索引,$or
查询的所有条款必须具有索引。否则,查询将是集合扫描。这在https://docs.mongodb.com/manual/reference/operator/query/or/#or-clauses-and-indexes
集合中的索引太多
集合中包含太多索引会以多种方式影响性能,例如,插入性能会受到影响,因为您将一个插入操作转换为多个(即集合的一个插入,以及您的每个索引的一个额外插入)采集)。太多看起来相似的索引对查询计划程序也是有害的,因为它需要从许多类似的索引中选择一个索引,而关于哪个索引的性能信息最少。
检查explain()
shell中的mongo
输出
explain()
shell中的mongo
输出是发现查询将使用哪个索引的最佳工具。通常,您希望避免任何COLLSCAN
阶段(这意味着集合扫描)和SORT_KEY_GENERATOR
阶段(这意味着MongoDB使用的内存排序限制为32MB,请参阅{{3} })。有关详细信息,请参阅https://docs.mongodb.com/manual/tutorial/sort-results-with-indexes/。
您可能需要查看有关索引和查询效果的相关页面:
话虽如此,我使用您的示例快速检查了mongo
shell(MongoDB 3.2.8)。您可以尝试在集合中添加这两个索引:
{blockNumber:1,transactionIndex:1,from:1}
{blockNumber:1,transactionIndex:1,to:1}
删除集合中的所有其他索引。这两个索引应该可以在你的两个示例查询中使用。