【问题标题】:MongoDB not using my indexMongoDB 不使用我的索引
【发布时间】:2017-09-20 15:54:35
【问题描述】:

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

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

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)。

【问题讨论】:

    标签: mongodb indexing compound-index


    【解决方案1】:

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

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

    如果您的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 之间没有太大区别,因为只使用了第一个字段。

    【讨论】:

    • 这可能是相关的。那么我可以改用$nin: [array list of all error ids] 吗?或者对于一个并非总是设置得非常无用的字段的非稀疏索引?
    • 或者更好的是:$ne: 999999。这是一个编号类型的参数。只是没用过。
    • 是的,两者都应该使用索引,但它与$ne: null 的查询不同。在这两种情况下你都会得到空值。如果您知道所有错误代码,您可以执行$in: [the list],但您可能会错过带有意外错误代码的文档。
    【解决方案2】:

    中奖计划是CACHED PLAN。 您可以尝试清除缓存计划。

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

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

    【讨论】:

    • 据我所知,提示是出于测试目的,您不能在聚合管道上设置索引提示。
    • 可以在聚合之前使用planCacheSetFilter函数
    猜你喜欢
    • 2018-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-08
    • 1970-01-01
    • 2014-09-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多