$skip and $limit in aggregation framework

后端 未结 2 1347
逝去的感伤
逝去的感伤 2020-11-29 00:24

When I read the document I found the following notes:

When a $sort immediately precedes a $limit in the pipeline, the $sort operation only maintains t

2条回答
  •  有刺的猬
    2020-11-29 01:00

    I found that it seems the sequence of limit and skip is immaterial. If I specify skip before limit, the mongoDB will make limit before skip under the hood.

    > db.system.profile.find().limit(1).sort( { ts : -1 } ).pretty()
    {
        "op" : "command",
        "ns" : "archiprod.userinfos",
        "command" : {
            "aggregate" : "userinfos",
            "pipeline" : [
                {
                    "$sort" : {
                        "updatedAt" : -1
                    }
                },
                {
                    "$limit" : 625
                },
                {
                    "$skip" : 600
                }
            ],
        },
        "keysExamined" : 625,
        "docsExamined" : 625,
        "cursorExhausted" : true,
        "numYield" : 4,
        "nreturned" : 25,
        "millis" : 25,
        "planSummary" : "IXSCAN { updatedAt: -1 }",
        /* Some fields are omitted */
    }
    

    What happens if I swtich $skip and $limit? I got the same result in terms of keysExamined and docsExamined.

    > db.system.profile.find().limit(1).sort( { ts : -1 } ).pretty()
    {
        "op" : "command",
        "ns" : "archiprod.userinfos",
        "command" : {
            "aggregate" : "userinfos",
            "pipeline" : [
                {
                    "$sort" : {
                        "updatedAt" : -1
                    }
                },
                {
                    "$skip" : 600
                },
                {
                    "$limit" : 25
                }
            ],
        },
        "keysExamined" : 625,
        "docsExamined" : 625,
        "cursorExhausted" : true,
        "numYield" : 5,
        "nreturned" : 25,
        "millis" : 71,
        "planSummary" : "IXSCAN { updatedAt: -1 }",
    }
    

    I then checked the explain result of the query. I found that totalDocsExamined is already 625 in the limit stage.

    > db.userinfos.explain('executionStats').aggregate([ { "$sort" : { "updatedAt" : -1 } }, { "$limit" : 625 }, { "$skip" : 600 } ])
    {
        "stages" : [
            {
                "$cursor" : {
                    "sort" : {
                        "updatedAt" : -1
                    },
                    "limit" : NumberLong(625),
                    "queryPlanner" : {
                        "winningPlan" : {
                            "stage" : "FETCH",
                            "inputStage" : {
                                "stage" : "IXSCAN",
                                "keyPattern" : {
                                    "updatedAt" : -1
                                },
                                "indexName" : "updatedAt_-1",
                            }
                        },
                    },
                    "executionStats" : {
                        "executionSuccess" : true,
                        "nReturned" : 625,
                        "executionTimeMillis" : 22,
                        "totalKeysExamined" : 625,
                        "totalDocsExamined" : 625,
                        "executionStages" : {
                            "stage" : "FETCH",
                            "nReturned" : 625,
                            "executionTimeMillisEstimate" : 0,
                            "works" : 625,
                            "advanced" : 625,
                            "docsExamined" : 625,
                            "inputStage" : {
                                "stage" : "IXSCAN",
                                "nReturned" : 625,
                                "works" : 625,
                                "advanced" : 625,
                                "keyPattern" : {
                                    "updatedAt" : -1
                                },
                                "indexName" : "updatedAt_-1",
                                "keysExamined" : 625,
                            }
                        }
                    }
                }
            },
            {
                "$skip" : NumberLong(600)
            }
        ]
    }
    

    And surprisingly, I found switching the $skip and $limit results in the same explain result.

    > db.userinfos.explain('executionStats').aggregate([ { "$sort" : { "updatedAt" : -1 } }, { "$skip" : 600 }, { "$limit" : 25 } ])
    {
        "stages" : [
            {
                "$cursor" : {
                    "sort" : {
                        "updatedAt" : -1
                    },
                    "limit" : NumberLong(625),
                    "queryPlanner" : {
                        /* Omitted */
                    },
                    "executionStats" : {
                        "executionSuccess" : true,
                        "nReturned" : 625,
                        "executionTimeMillis" : 31,
                        "totalKeysExamined" : 625,
                        "totalDocsExamined" : 625,
                        /* Omitted */
                    }
                }
            },
            {
                "$skip" : NumberLong(600)
            }
        ]
    }
    

    As you can see, even though I specified $skip before $limit, in the explain result, it's still $limit before $skip.

提交回复
热议问题