Mongo $or 查询范围是在内存中排序吗?
Posted
技术标签:
【中文标题】Mongo $or 查询范围是在内存中排序吗?【英文标题】:Mongo $or query with ranges is doing an in-memory sort? 【发布时间】: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]"
]
]
【问题讨论】:
【参考方案1】:$or
的每个分支都可以使用一个索引,但是您仍然有两个结果集,如果您在顶部应用排序,则数据库必须在内存中对结果进行排序。对 $or 运算符进行排序会产生内存排序似乎是合理的。
【讨论】:
但是为什么不能像第二个查询那样进行合并排序呢?它在第二个查询中也有 2 个阶段。是不是各个阶段本身没有排序,所以不能合并? 什么是归并排序? 我认为归并排序不正确。这是一个排序合并,所以合并2个排序的数组。 我不明白你在说什么。如果您暗示 MongoDB 的行为与其文档(或其他已发布的声明)相矛盾,请参考您认为相矛盾的文档。 抱歉不清楚。我指的是查询 2 计划中的 SORT_MERGE 阶段。我在归并排序中命名,但我认为这意味着合并 2 个排序数组而不是使用归并排序排序。所以我只是对命名感到困惑。以上是关于Mongo $or 查询范围是在内存中排序吗?的主要内容,如果未能解决你的问题,请参考以下文章
Mongodb:从 mongo shell 中的 ObjectId 执行日期范围查询
OperationFailed Sort operation used more than the maximum 33554432 bytes of RAM. Add an index, or sp