mongodb executionStats时间与实际执行不同



我使用M10 mongodb图集(2GB RAM,2CPU(进行测试。我收藏了101330份文件。每个文档看起来都像

{
_id: ObjectId("618d3bf93de582a797f28df3"),
applicantName: 'a57cgMwpX6EsMca',
amount: 6391,
status: 'Pending',
date: ISODate("2021-11-11T15:51:21.115Z")
}

使用mongoshell,我运行查询db.test.find({}(.toArray((来返回所有记录。它不是在1分钟内完成的。我很惊讶花了这么长时间。这是因为我使用的资源太少还是很正常。运行explain命令查看db.test.find({}(.deexplain("executionStats"(的详细信息会得到结果。

{
queryPlanner: {
plannerVersion: 1,
namespace: 'policymatrix_dev.indextest',
indexFilterSet: false,
parsedQuery: {},
winningPlan: { stage: 'COLLSCAN', direction: 'forward' },
rejectedPlans: []
},
executionStats: {
executionSuccess: true,
nReturned: 101330,
executionTimeMillis: 26,
totalKeysExamined: 0,
totalDocsExamined: 101330,
executionStages: {
stage: 'COLLSCAN',
nReturned: 101330,
executionTimeMillisEstimate: 2,
works: 101332,
advanced: 101330,
needTime: 1,
needYield: 0,
saveState: 101,
restoreState: 101,
isEOF: 1,
direction: 'forward',
docsExamined: 101330
}
},
serverInfo: {
host: '',
port: 27017,
version: '4.4.10',
gitVersion: ''
},
ok: 1,
'$clusterTime': {
clusterTime: Timestamp({ t: 1636723868, i: 1 }),
signature: {
hash: 
keyId: Long("6968661901790150660")
}
},
operationTime: Timestamp({ t: 1636723868, i: 1 })
}

从结果中,我可以看到它给出的executionTimeMillis等于26,这是一个非常小的值。现在我很困惑为什么统计数据的实际查询执行时间和executionTimeMillis有差异。它们是相同的还是不同的。

为了添加更多内容,我在AWS lambda函数中运行了相同的查询。它在5314毫秒内完成。这真的很令人困惑。

module.exports.handler = async() => {
try {
const db = await connectDB("database");
const start = new Date();
const response = await test.find({});
const end = new Date();
console.log("time required", end - start)  // returns 5314
console.log(response.length)   // returns 101330
return {success: true}
}

运行db.test.find({}).explain("executionStats")时,您将返回一个文档。执行时间将包括从磁盘/缓存中提取所花费的时间,但这些文档实际上从未离开服务器。

当你运行db.test.find({}).toArray()时,有很多你看不到的事情在幕后发生。

该请求的解剖结构类似于:

  1. 驱动程序发送";查找";向服务器发出请求
  2. mongod获取全局锁、数据库锁和集合锁
  3. mongod创建一个新的游标来检索文档
  4. 当文档从存储引擎返回时,mongod构建一个响应对象
  5. 当响应对象达到BSON对象大小限制16MB时,mongod释放锁并将文档发送给驱动程序
  6. 驱动程序接收包含多个文档的响应对象
  7. 驱动程序迭代那些返回的文档,将每个文档推送到一个数组中
  8. 当响应对象用完时,向服务器发送getMore请求
  9. mongod重新获取锁并恢复光标
  10. 重复步骤4-9,直到光标用尽为止
  11. 将最终数组返回给调用进程

如果你有10万个文件,平均大小约为1公里,那么至少需要6次往返。

解释报告的时间将包括步骤2、3和4。如果在解释和实际运行之间,缓存、内存、磁盘或CPU利用率发生了任何变化,那么这些步骤将不会花费相同的时间。

实际执行也会暂停步骤5、6、7和8的服务器端执行,因此,如果网络或客户端阵列处理不是即时的(即在现实世界中(,则实际执行将需要更长的时间。

如果您想了解具体情况,可以查看客户端和/或服务器上的网络数据包,以了解每个批次的请求和完成时间。

您还可以调整探查器设置(如slowms(,以便为每个批获取一个日志条目,其中详细说明使用的锁,以及从磁盘读取的时间。

MongoDB使用LRU(Least Recent First(算法从内存中丢弃最近的数据,尤其是在资源较少的情况下。因此,似乎发生的情况是,数据位于存储中,并且很长一段时间没有使用,虚拟机将需要一些时间将其加载到内存中并进行处理,尤其是当您不使用索引时,因此您运行查询,它将处理>1分钟的时间,但当您在之后立即运行解释("executionStats"(时,数据已经在内存中,估计处理它所需的时间更少。如果您重新启动服务或刷新缓存并在实际查询之前执行解释("Execution_Stats"(,它将向您显示>1分钟时间(当然这里取决于后端存储利用率(

此外,M10和M20集群层支持开发环境和低流量应用程序,它们不适用于生产和高性能活动。

最新更新