Mongodb即使在创建了适当的索引之后也会扫描大量文档

Mongodb即使在创建了适当的索引之后也会扫描大量文档,mongodb,Mongodb,我在mongodb查询中遇到了一个问题,即使创建了一个适当的索引来对结果进行排序,文档扫描仍然非常高。 下面是查询 db.ratebus.find({ $and: [{ _id.trg: { $in: [54875973] } }, { rating: { $gte: 3 } }] }).sort({ revType: -1, updated_a

我在mongodb查询中遇到了一个问题,即使创建了一个适当的索引来对结果进行排序,文档扫描仍然非常高。 下面是查询

db.ratebus.find({
    $and: [{
        _id.trg: {
            $in: [54875973]
        }
    }, {
        rating: {
            $gte: 3
        }
    }]
}).sort({
    revType: -1,
    updated_at: -1
}).hint({
    _id.trg: 1,
    rating: -1,
    revType: -1,
    updated_at: -1
}).limit(10)
下面是分析器的输出

2018-10-08T13:03:15.986+0530 I COMMAND  [conn1370938] command jdsocial.ratebus command: find {
    find: "ratebus",
    filter: {
        $and: [{
            _id.trg: {
                $in: [54875973]
            }
        }, {
            rating: {
                $gte: 3
            }
        }]
    },
    sort: {
        revType: -1,
        updated_at: -1
    },
    hint: {
        _id.trg: 1,
        rating: -1,
        revType: -1,
        updated_at: -1
    },
    limit: 10
}
planSummary: IXSCAN {
    _id.trg: 1.0, rating: -1.0, revType: -1.0, updated_at: -1.0
}
keysExamined: 37423 docsExamined: 37423 hasSortStage: 1 cursorExhausted: 1 keyUpdates: 0 writeConflicts: 0 numYields: 292 nreturned: 10 reslen: 4047 locks: {
    Global: {
        acquireCount: {
            r: 586
        },
        acquireWaitCount: {
            r: 26
        },
        timeAcquiringMicros: {
            r: 179979
        }
    },
    Database: {
        acquireCount: {
            r: 293
        }
    },
    Collection: {
        acquireCount: {
            r: 293
        }
    }
} protocol:op_query 692ms
这里可以清楚地看到,对于10条记录的限制,它正在扫描37423个文档。任何帮助都将不胜感激

db中的样本记录:

{
    "_id" : {
        "src" : 2584095,
        "trg" : 54877444
    },
    "revid" : "0805639673",
    "rating" : 2,
    "age" : ISODate("2012-11-14T15:41:09Z"),
    "updated_at" : ISODate("2012-11-14T15:41:09Z"),
    "hasrev" : 0,
    "revType" : 0,
    "has_rev" : false,
    "rev" : ""
},
{
    "_id" : {
        "src" : 38266391,
        "trg" : 54878562
    },
    "revid" : "0805639674",
    "rating" : 4,
    "age" : ISODate("2012-11-14T15:41:14Z"),
    "updated_at" : ISODate("2012-11-14T15:41:14Z"),
    "hasrev" : 0,
    "revType" : 0,
    "has_rev" : false,
    "rev" : "",
    "comment_id" : NumberLong("1531272078171327")
}
创建的索引:

{
    "v" : 1,
    "key" : {
        "_id.trg" : 1,
        "rating" : -1,
        "revType" : -1,
        "updated_at" : -1
    },
    "name" : "_id.trg_1_rating_-1_revType_-1_updated_at_-1",
    "ns" : "jdsocial.ratebus"
}

排序部分应位于中。你有什么索引

{
    "_id.trg" : 1,
    "rating" : -1,
    "revType" : -1,
    "updated_at" : -1
}
不支持排序方式

{
    revType: -1,
    updated_at: -1
}
有索引的字段应具有正确顺序的索引字段:

{
    "revType" : -1,
    "updated_at" : -1,
    "_id.trg" : 1,
    "rating" : -1
}

排序部分应位于中。你有什么索引

{
    "_id.trg" : 1,
    "rating" : -1,
    "revType" : -1,
    "updated_at" : -1
}
不支持排序方式

{
    revType: -1,
    updated_at: -1
}
有索引的字段应具有正确顺序的索引字段:

{
    "revType" : -1,
    "updated_at" : -1,
    "_id.trg" : 1,
    "rating" : -1
}

为了完成@Alex Blex的回答,我想说排序部分应该在索引前缀中,因为您在查询中使用了$in

让我解释一下:MongoDB使用索引的策略如下:1)相等-2)排序-3)范围。当您在查询的筛选器部分中使用$in时,这一部分属于策略的“范围”部分。因此,排序阶段具有优先权,它不能正确使用索引,因为它与索引前缀不匹配


因此,有两种解决方案:如Alex所说,创建一个新的索引,或者将
\u id.trg:{$in:[54875973]}
替换为
\u id.trg:{$eq:[54875973]}
。唯一要选择的问题是“我真的需要一系列ID来进行此查询吗?”

要完成@Alex Blex的回答,我会说排序部分应该在索引前缀中,因为您在查询中使用$in

让我解释一下:MongoDB使用索引的策略如下:1)相等-2)排序-3)范围。当您在查询的筛选器部分中使用$in时,这一部分属于策略的“范围”部分。因此,排序阶段具有优先权,它不能正确使用索引,因为它与索引前缀不匹配


因此,有两种解决方案:如Alex所说,创建一个新的索引,或者将
\u id.trg:{$in:[54875973]}
替换为
\u id.trg:{$eq:[54875973]}
。唯一要选择的问题是“我真的需要一系列ID来进行此查询吗?”

您能提供您的文档样本和创建的索引吗?添加了样本记录和索引使用combine
{revType:-1,更新地址:-1}
,可能会对您有所帮助。@IftekharDani它已经存在了,看起来您还没有为特定的两个字段创建
索引
{revType:-1,updated_at:-1}
您能提供您的文档样本和创建的索引吗?添加了样本记录和索引创建索引,并将
{revType:-1,updated_at:-1}
,可能会对您有所帮助。@IftekharDani它已经存在了,看起来您还没有为特定的两个字段创建
索引
{revType:-1,更新时间:-1}
请注意,只要前面的所有列都是固定的,它就不必是前缀。因此
\u id.trg
可能会保持在前面(但前提是
$in
实际上只是一个相等匹配,并且不需要较长的选项列表)。请注意,只要前面的所有列都是固定的,它就不必是前缀。因此,
\u id.trg
可能会保持领先(但前提是
$in
实际上只是一个相等匹配,并且不需要更长的选项列表)。