【问题标题】:Mongo $or query with ranges is doing an in-memory sort?Mongo $or 查询范围是在内存中排序吗?
【发布时间】:2020-10-01 16:06:09
【问题描述】:

我遇到了一种特殊情况,其中一个查询似乎是在进行内存排序。查询 1 是执行内存排序的查询,而查询 2 正确执行合并排序。

查询有几个部分,所以我想知道哪个部分导致查询排序在内存中完成?

我确实有一个解决方法,但我想知道这背后的原因。它们都有 2 个输入级,所以我不确定是什么原因。

架构:

schema = {
    date: Date, // date that can change
    createTime: Date, // create time of document
    value: Number
}

索引:

schema.index({value: 1, createTime: -1, date: 1});

查询 1:我在顶层有 $or 以避免使用不正确的索引:MongoDB query to slow when using $or operator

db.getCollection('dates').find({
    $or: [
        {value: {$in: [1, 2]}, date: null},
        {value: {$in: [1, 2]}, date: {$gt: ISODate("2020-06-16T23:59:59.999Z")}}
   ]
}).sort({createTime:-1}).explain()

查询 1 计划:如您所见,它在内存中进行排序。我不确定发生这种情况的确切原因。

{
    "stage" : "SUBPLAN",
    "inputStage" : {
        "stage" : "FETCH",
        "inputStage" : {
            "stage" : "SORT",
            "sortPattern" : {
                "createTime" : -1.0
            },
            "inputStage" : {
                "stage" : "SORT_KEY_GENERATOR",
                "inputStage" : {
                    "stage" : "OR",
                    "inputStages" : [ 
                        {
                            "stage" : "FETCH",
                            "filter" : {
                                "date" : {
                                    "$eq" : null
                                }
                            },
                            "inputStage" : {
                                "stage" : "IXSCAN",
                                "keyPattern" : {
                                    "value" : 1,
                                    "createTime" : -1,
                                    "date" : 1
                                },
                                "indexName" : "value_1_createTime_-1_date_1",
                                "isMultiKey" : false,
                                "multiKeyPaths" : {
                                    "value" : [],
                                    "createTime" : [],
                                    "date" : []
                                },
                                "isUnique" : false,
                                "isSparse" : false,
                                "isPartial" : false,
                                "indexVersion" : 2,
                                "direction" : "forward",
                                "indexBounds" : {
                                    "value" : [ 
                                        "[1.0, 1.0]", 
                                        "[2.0, 2.0]"
                                    ],
                                    "createTime" : [ 
                                        "[MaxKey, MinKey]"
                                    ],
                                    "date" : [ 
                                        "[undefined, undefined]", 
                                        "[null, null]"
                                    ]
                                }
                            }
                        }, 
                        {
                            "stage" : "IXSCAN",
                            "keyPattern" : {
                                "value" : 1,
                                "createTime" : -1,
                                "date" : 1
                            },
                            "indexName" : "value_1_createTime_-1_date_1",
                            "isMultiKey" : false,
                            "multiKeyPaths" : {
                                "value" : [],
                                "createTime" : [],
                                "date" : []
                            },
                            "isUnique" : false,
                            "isSparse" : false,
                            "isPartial" : false,
                            "indexVersion" : 2,
                            "direction" : "forward",
                            "indexBounds" : {
                                "value" : [ 
                                    "[1.0, 1.0]", 
                                    "[2.0, 2.0]"
                                ],
                                "createTime" : [ 
                                    "[MaxKey, MinKey]"
                                ],
                                "date" : [ 
                                    "(new Date(1592351999999), new Date(9223372036854775807)]"
                                ]
                            }
                        }
                    ]
                }
            }
        }
    }
}

查询 2:

db.getCollection('dates').find({
    value: {$in: [1, 2]},
    date: {$not: {$lte: ISODate("2020-06-16T23:59:59.999Z")}}
}).sort({createTime:-1}).explain()

查询 2 计划:我使用的解决方法查询,它成功进行了合并排序。

{
    "stage" : "FETCH",
    "inputStage" : {
        "stage" : "SORT_MERGE",
        "sortPattern" : {
            "createTime" : -1.0
        },
        "inputStages" : [ 
            {
                "stage" : "IXSCAN",
                "keyPattern" : {
                    "value" : 1,
                    "createTime" : -1,
                    "date" : 1
                },
                "indexName" : "value_1_createTime_-1_date_1",
                "isMultiKey" : false,
                "multiKeyPaths" : {
                    "value" : [],
                    "createTime" : [],
                    "date" : []
                },
                "isUnique" : false,
                "isSparse" : false,
                "isPartial" : false,
                "indexVersion" : 2,
                "direction" : "forward",
                "indexBounds" : {
                    "value" : [ 
                        "[1.0, 1.0]"
                    ],
                    "createTime" : [ 
                        "[MaxKey, MinKey]"
                    ],
                    "date" : [ 
                        "[MinKey, true]", 
                        "(new Date(1592351999999), MaxKey]"
                    ]
                }
            }, 
            {
                "stage" : "IXSCAN",
                "keyPattern" : {
                    "value" : 1,
                    "createTime" : -1,
                    "date" : 1
                },
                "indexName" : "value_1_createTime_-1_date_1",
                "isMultiKey" : false,
                "multiKeyPaths" : {
                    "value" : [],
                    "createTime" : [],
                    "date" : []
                },
                "isUnique" : false,
                "isSparse" : false,
                "isPartial" : false,
                "indexVersion" : 2,
                "direction" : "forward",
                "indexBounds" : {
                    "value" : [ 
                        "[2.0, 2.0]"
                    ],
                    "createTime" : [ 
                        "[MaxKey, MinKey]"
                    ],
                    "date" : [ 
                        "[MinKey, true]", 
                        "(new Date(1592351999999), MaxKey]"
                    ]
                }
            }
        ]
    }
}

【问题讨论】:

    标签: mongodb sorting mongoose indexing mongodb-query


    【解决方案1】:

    $or 的每个分支都可以使用一个索引,但是您仍然有两个结果集,如果您在顶部应用排序,则数据库必须在内存中对结果进行排序。对 $or 运算符进行排序会产生内存排序似乎是合理的。

    【讨论】:

    • 但是为什么不能像第二个查询那样进行合并排序呢?它在第二个查询中也有 2 个阶段。是不是各个阶段本身没有排序,所以不能合并?
    • 什么是归并排序?
    • 我认为归并排序不正确。这是一个排序合并,所以合并2个排序的数组。
    • 我不明白你在说什么。如果您暗示 MongoDB 的行为与其文档(或其他已发布的声明)相矛盾,请参考您认为相矛盾的文档。
    • 抱歉不清楚。我指的是查询 2 计划中的 SORT_MERGE 阶段。我在归并排序中命名,但我认为这意味着合并 2 个排序数组而不是使用归并排序排序。所以我只是对命名感到困惑。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-20
    • 2023-04-08
    • 1970-01-01
    • 2020-11-05
    • 1970-01-01
    • 1970-01-01
    • 2019-09-18
    相关资源
    最近更新 更多