Search code examples
mongodbmongodb-indexes

MongoDB index not used when sorting, although prefix matches


I'm trying to fetch a set of records in the most efficient way from MongoDB, but it goes wrong when I add a sorting stage to the pipeline. The server does not use my intended index. According to the documentation it should however match the prefix: https://docs.mongodb.com/manual/tutorial/sort-results-with-indexes/#sort-and-non-prefix-subset-of-an-index

I have an index which looks like this:

{
    "v" : 2,
    "key" : {
        "account_id" : 1,
        "cdr_block" : 1,
        "billing.total_billed" : 1,
        "times.created" : -1 
     },
     "name" : "IDX_by_account_and_block_sorted"
}

So I would suppose that when I filter on account_id, cdr_block and billing.total_billed, followed by a sort on times.created, the index would be used.

However that is not the case; when I check the query explanations in MongoDB shell; this one does NOT use the index, but uses an index that is composed of times.created only, so it takes a few minutes:

db.getCollection("cdr").aggregate(
    [
        { 
            "$match" : {
                "account_id" : 160.0, 
                "cdr_block" : ObjectId("5d11e0364f853f15824aff47"), 
                "billing.total_billed" : {
                    "$gt" : 0.0
                }
            }
        }, 
        { 
            "$sort" : {
                "times.created" : -1.0
            }
        }
    ], 
    { 
        "allowDiskUse" : true
    }
);

If I leave out the $sort stage, it does use my above mentioned index.

I was thinking that it was perhaps due to the fact that it's an aggregation, but this 'regular' query also doesn't use the index:

db.getCollection("cdr").find({ 
    "account_id" : 160.0, 
    "cdr_block" : ObjectId("5d11e0364f853f15824aff47"), 
    "billing.total_billed" : {
        "$gt" : 0.0
    }
}).sort({"times.created" : -1 });


Solution

  • $sort Operator and Performance

    $sort operator can take advantage of an index when placed at the beginning of the pipeline or placed before the $project, $unwind, and $group aggregation operators. If $project, $unwind, or $group occur prior to the $sort operation, $sort cannot use any indexes.