Mongo根据级别范围高效查询日志集合

时间:2016-02-16 10:12:24

标签: mongodb nosql

我有一个用于存储服务器日志的上限集合:

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个文档。

有更好的方法吗?

1 个答案:

答案 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并运行其他一些查询。