mongo 在聚合中匹配前排序

mongo sort before match in aggregation

给定一个包含几百万个文档的集合,如下所示:

{
    organization: ObjectId("6a55b2f1aae2fe0ddd525828"),
    updated_on: 2019-04-18 14:08:48.781Z
}

和 2 个索引,在键 {organization: 1} 和 {updated_on: 1}

以下查询需要 ages 到 return:

db.getCollection('sessions').aggregate([
        {
                "$match" : {
                        "organization" : ObjectId("5a55b2f1aae2fe0ddd525827"),
                }
        },
        {
                "$sort" : {
                        "updated_on" : 1
                }
        }
])

需要注意的一点是,结果是 0 个匹配项。经过进一步调查,explain() 中的规划器实际上 return 如下:

{
    "stage" : "FETCH",
    "filter" : {
        "organization" : {
            "$eq" : ObjectId("5a55b2f1aae2fe0ddd525827")
        }
    },
    "inputStage" : {
        "stage" : "IXSCAN",
        "keyPattern" : {
            "updated_on" : 1.0
        },
        "indexName" : "updated_on_1",
        "isMultiKey" : false,
        "multiKeyPaths" : {
            "updated_on" : []
        },
        "isUnique" : false,
        "isSparse" : false,
        "isPartial" : false,
        "indexVersion" : 2,
        "direction" : "forward",
        "indexBounds" : {
            "updated_on" : [ 
                "[MinKey, MaxKey]"
            ]
        }
    }
}

MongoDB 会使用 $sort 上的索引,因为这是一个繁重的操作,即使之前匹配也会限制要排序的结果,

您可以强制使用 $match:

的索引
db.collection.aggregate(pipeline, {hint: "index_name"})

或者创建一个更好的索引来解决这两个问题,查看更多信息here

db.collection.createIndex({organization: 1, updated_on:1}, {background: true})

Why would Mongo combine these into one stage and decide to to sort ALL documents BEFORE filtering? How can I prevent that?

排序确实发生在比赛阶段之后。查询计划 没有 显示 SORT 阶段 - 这是因为排序键 updated_on 上有一个索引。如果删除 updated_on 字段上的索引,您 在查询计划中看到一个 SORT 阶段(并且它将是内存中排序)。

Explain Results - sort stage


一些想法:

(i) 您可以使用复合索引,而不是两个单字段索引:

{ organization: 1, updated_on: 1 }

它将正常工作。在 Sort and Non-prefix Subset of an Index.

上查看此主题

(ii) 此外,find() 查询可以完成相同的工作,而不是聚合:

db.test.find( { organization : ObjectId("5a55b2f1aae2fe0ddd525827") } ).sort( { updated_on: 1 } )

注意:请使用 explain() 进行验证并查看它们的性能。另外,尝试使用 executionStats 模式。