1

我有一个包含数百万条记录的日志集合。创建新索引需要“永远”。所以最好使用现有的索引。

现在我想获取某些错误代码的出现次数。我使用这个查询,并且在功能上它工作正常:

db.getCollection('logs.res').aggregate([
    {
       $match:{    
           timeStamp: {
               $gte: new Date('2017-05-01').getTime(), // timeStamp is Number
               $lt : new Date('2017-05-02').getTime()  // of ms since epoch
           },
           'objData.@.ErrorCode': {
               $ne: null
           }
        }
    },
    {
        $group: {
            _id: '$objData.@.ErrorCode',
            count: {$sum: 1}
        }
    },
    {
        $sort: { count: -1}
    }
]);

问题是仅仅执行一天就需要将近 10 秒。我假设将使用以下索引timeStamp_-1_objData.@.ErrorCode_1

{
    "timeStamp" : -1,
    "objData.@.ErrorCode" : 1
}

然而,MongoDB 似乎坚持使用一些timeStamp: 1索引(以及一些与查询无关的其他索引),并扫描所有结果以查看是否有一些响应可能ErrorCode附加,即使这些信息应该在索引中。

这是explain()

在此处输入图像描述

  • 有没有办法使用 timeStamp_-1_objData.@.ErrorCode_1 索引来加快速度?
  • 为什么使用这个索引?我可能误解了此查询中如何使用索引。

在 OSX 上运行 MongoDB 3.2.7。

注意:我也尝试$empty: true过代替$ne: null. $empty它产生相同的结果,但有人说如果你想使用复合索引就不能使用。不过,有关 Stack Overflow 的许多问题都是旧的(mongo 2.x)。

4

2 回答 2

2

常规 mongodb 索引使用字段值和类型来构建树。

查询喜欢$empty: true$ne: null没有任何类型的参数,并且不能从此类索引中受益。这是一种特殊情况,需要特殊的稀疏索引

如果您的timeStamp_-1_objData.@.ErrorCode_1索引创建为:

db.getCollection('logs.res').createIndex(
    {
        "timeStamp" : -1,
        "objData.@.ErrorCode" : 1
    },
    { sparse: true }
)

它应该最好地支持您的查询。否则,和之间没有太大区别timeStamp_-1_objData.@.ErrorCode_1timeStamp_1_module_1_etc因为使用了唯一的第一个字段。

于 2017-09-20T16:58:28.630 回答
2

获胜计划是CACHED PLAN。您可以尝试清除缓存计划。

db.getCollection('logs.res').getPlanCache().clear()

如果清理缓存后,Mongo 仍然使用错误的索引。您可以尝试设置查询计划或使用“提示”来强制索引

于 2017-09-20T16:03:55.417 回答