我有一个用于存储服务器日志的上限集合:
var schema = new mongoose.Schema({
level: { type: Number, required: true },
...
}, { capped: 64 * 1024 * 1024, versionKey: false });
我无法确定如何有效地按level
范围查询日志。这是我想要运行的示例查询:
db.getCollection('logs').find({
level: { $gte: 2, $lte: 6 }
}).sort({ _id: -1 }).limit(500)
{ _id: 1, level: 1 }
上的索引没有任何意义,因为_id
是唯一的,并且每个都只有一个level
,所以在最坏的情况下整个收集将被检查。
如果我在{ level: 1, _id: -1 }
上编入索引,在最坏的情况下,Mongo将所有日志拉为2,3,4,5,6级加入并手动排序,因此性能非常糟糕。有时它也决定使用{ _id: 1 }
索引,这也很糟糕。
它可以一次遍历这6个索引,并在检查最多504个文档时获得结果。或者它只能从每个级别拉出前500个结果,因此它最多可以排序2500个文档。但它不会,但就范围查询而言,Mongo只是愚蠢。
我能想到的最快的解决方案是在客户端上实现最后提到的方法,因此运行5个查询然后手动合并它们:
db.getCollection('logs').find({ level: 2 }).sort({ _id: -1 }).limit(500)
db.getCollection('logs').find({ level: 2 }).sort({ _id: -1 }).limit(500)
db.getCollection('logs').find({ level: 3 }).sort({ _id: -1 }).limit(500)
...
合并可以在客户端的O(n)
中完成,只有7个日志级别,因此最多可执行7个查询,并从数据库中提取3500个文档。
有更好的方法吗?
答案 0 :(得分:1)
由于您只有7个级别,因此使用{ level: 1, _id: -1 }
查询可能需要考虑$or
索引:
db.logs.find({$or:[
{level: 2},
{level: 3},
{level: 4},
{level: 5},
{level: 6}
]}).sort({_id:-1}).limit(500)
由于它是相等条件,它应该使用索引,但我从未在上限集合上尝试过。
我会试一试并运行explain()
确认它有效,然后可能enabled profiler并运行其他一些查询。