gpt4 book ai didi

MongoDB 查询超时,即使我索引了字段

转载 作者:可可西里 更新时间:2023-11-01 10:00:03 25 4
gpt4 key购买 nike

我正在对一个非常大的集合(5 亿文档)运行查询,该查询有时会超时(6 分钟)或花费很长时间(3-6 分钟)。

我索引了所有相关字段(没有复合索引):Tag、trophies、battleLogMonitorFrequency、profileRefreshedAt 被索引并且 totalIndexSize 低于我内存的 60%(45gb 索引大小为 153gb,可用于 mongodb)。

const oneHour: number = 1000 * 60 * 60;
const projection: {} = { tag: 1 };
const filter: {} = {
battleLogMonitorFrequency: interval,
profileRefreshedAt: { $lt: new Date(snapDate.valueOf() - interval * oneHour) }
};
const profileCursorTrophies: QueryCursor<IPlayerProfileModel> = PlayerProfile.find(filter, projection).sort({ trophies: -1 })
.limit(50000).lean().cursor();
await profileCursorTrophies.eachAsync(
(profile: IPlayerProfileModel) => {
outDatedProfileTags.push(profile.tag);
},
{ parallel: 100 }
);

我的问题:

为什么我要花这么长时间(甚至超时)才能得到排序结果?我的印象是索引我排序和过滤的字段应该足以满足该查询?

编辑: 完整查询解释结果:https://hastebin.com/ofixobasix.bash

编辑 2: getIndexes() 的输出:https://hastebin.com/azayojokez.scala

编辑 3:在建议为我的查询使用复合索引后,我注意到结果根本没有改变。查询仍然需要很长时间才能执行。查看以下解释结果:https://hastebin.com/ragixuqaci.bash

已添加此索引:

    {
"v" : 2,
"key" : {
"battleLogMonitorFrequency" : 1,
"profileRefreshedAt" : 1,
"trophies" : -1
},
"name" : "battleLogMonitorFrequency_1_profileRefreshedAt_1_trophies_-1",
"ns" : "dbname.playerprofiles",
"background" : true
}

最佳答案

你是这样走的:

您创建了复合索引 {battleLogMonitorFrequency: 1, profileRefreshedAt: 1, trophies: -1} 并在排序期间遇到内存不足问题。

errmsg: \"Sort operation used more than the maximum 33554432 bytes of RAM. Add an index, or specify a smaller limit.\""

I followed below steps to solve it.


1。创建了 1 亿条记录的集合

db.myc.count()  > 100034080

我的查询是这样的:

db.myc.find({field1  : 1, field2: {$lt : 800}}).sort({field3 : 1})

查询应该返回3890 万条记录(我知道这很大但我想对其进行负载测试)


<强>2。然后我创建了索引 {field1 : 1, field2: 1, field3:1}

执行查询并得到内存不足的排序。在这里,我能够重现 OP 的问题。

(解释片段)

"executionStats" : {
"executionSuccess" : false,
"errorMessage" : "Exec error resulting in state FAILURE :: caused by :: errmsg: \"Sort operation used more than the maximum 33554432 bytes of RAM. Add an index, or specify a smaller limit.\"",
"errorCode" : 96,
"nReturned" : 0,
"executionTimeMillis" : 19033,
"totalKeysExamined" : 322639,
"totalDocsExamined" : 322639,
"executionStages" : {

"inputStage" : {

"inputStage" : {

"inputStage" : {

"indexName" : "field1_1_field2_1_field3_1",
"isMultiKey" : false,
"multiKeyPaths" : {
"field1" : [ ],
"field2" : [ ],
"field3" : [ ]
},

}
}
}
}
}

<强>3。 (解决方案)更改了索引中字段的顺序 {field1 : 1, field3: 1, field2:1}重新执行查询,这次我得到了回复。而且 totalDocsExaminednReturned 实际上是相同的,这表明索引被 Mongo 查询优化器完美使用。

"executionStats" : {
"executionSuccess" : true,
"nReturned" : 38901493,
"executionTimeMillis" : 1571781,
"totalKeysExamined" : 38902394,
"totalDocsExamined" : 38901493,
"executionStages" : {

"inputStage" : {

"indexName" : "field1_1_field3_1_field2_1",
"isMultiKey" : false,
"multiKeyPaths" : {
"field1" : [ ],
"field3" : [ ],
"field2" : [ ]
},

}
}
}

尽管我的查询执行时间很长,但这是显而易见的,因为它返回(不切实际的)38.9m 记录。我更关心的是 mongo 使用了正确的索引吗?答案是肯定的。


解释:OP 的查询是 Mongo 的 Equality, Range, Sort 问题的典型场景。当在 equality field - range field - sort field 上有索引时,Mongo 仅将其用于过滤器而不用于排序。因此,排序是在内存中执行的。为了解决这个问题,我们需要将范围字段保留在复合索引的末尾。

我找到了一个 good article更好地解释场景。

关于MongoDB 查询超时,即使我索引了字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49131449/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com