mongodb - 聚合中的 $lookup 非常慢
问题描述
我正在使用$lookup
加入两个集合进行计数,但executionStats
显示查询非常慢(单个查询每个查询 500+ms)。这是集合大小:
> db.visit.find({}).count()
8174
> db.links.find({}).count()
89
这是聚合的查找策略:
> db.visit.explain('executionStats').aggregate([{"$lookup": {from: "links", localField: "alias", foreignField: "alias", as: "url"}}])
结果是:
{
"stages": [
{
"$cursor": {
"queryPlanner": {
"plannerVersion": 1,
"namespace": "redir.visit",
"indexFilterSet": false,
"parsedQuery": {
},
"queryHash": "8B3D4AB8",
"planCacheKey": "8B3D4AB8",
"winningPlan": {
"stage": "COLLSCAN",
"direction": "forward"
},
"rejectedPlans": []
},
"executionStats": {
"executionSuccess": true,
"nReturned": 8174,
"executionTimeMillis": 642,
"totalKeysExamined": 0,
"totalDocsExamined": 8174,
"executionStages": {
"stage": "COLLSCAN",
"nReturned": 8174,
"executionTimeMillisEstimate": 0,
"works": 8176,
"advanced": 8174,
"needTime": 1,
"needYield": 0,
"saveState": 9,
"restoreState": 9,
"isEOF": 1,
"direction": "forward",
"docsExamined": 8174
}
}
},
"nReturned": NumberLong(8174),
"executionTimeMillisEstimate": NumberLong(7)
},
{
"$lookup": {
"from": "links",
"as": "url",
"localField": "alias",
"foreignField": "alias"
},
"nReturned": NumberLong(8174),
"executionTimeMillisEstimate": NumberLong(643)
}
]
}
为什么以及如何解决它?
解决方案
该管道在第一阶段没有任何过滤,因此当您执行聚合时,隐含的第一步是“从访问集合中获取所有文档”
然后将每个文档传递到管道中,该$lookup
阶段对每个文档的“链接”集合执行查找查询。
如果您在 links 集合中没有索引{alias: 1}
,则它必须检查该集合中的每个文档以从源文档中获取与“别名”字段匹配的任何文档。
在未索引的情况下,这意味着聚合查询将需要检查这 89 个链接文档中的每一个文档 8174 次,总共需要 727486 个文档检查。每次检查都将涉及每个文档中 1 个字段的字符串比较(假设“别名”是一个字符串)。
总运行时间为 643 毫秒,平均每毫秒检查约 1131 个文档,这意味着每微秒 1 个字符串比较。
这实际上听起来并不算太糟糕。
如果您希望它执行得更快,请尽量减少检查的文档数量。
有两种主要方法可以实现这一点:
- 不要使用别名,将链接信息直接放在“访问”文档中。这将完全消除在获取期间进行 $lookup 的需要,但代价是在编写“访问”文档时进行查找
- 在“链接”集合中创建一个索引
{ alias: 1 }
这将替换 89 * 8174 文档检查和 8174 索引扫描,然后仅检查具有匹配别名的文档。假设每个“访问”仅包含 1 个别名,并且每个别名仅存在于一个“链接”文档中,这会将总数从 727486 个文档检查减少到 8174 个索引扫描 + 8174 个文档检查。
推荐阅读
- c# - 将 WPF 控件转换为 PDF
- react-native - 从 github 打开 react-native 项目时构建失败
- php - PHP Mysqli 数据库连接池以避免最大用户数
- tmux - 从 tmux 命令行创建新窗格
- security - 如何通过 IP 地址限制对我的 subversion 服务器(即 svnserve)的访问,所以只有我的 IP 可以签出、提交等?
- python - Json数据排序PANDAS,python
- php - PHP 正则表达式字符串和减法部分
- apache-spark - 如何在 ElasticSearch 中创建索引并从流式查询中推送数据?
- javascript - javascript onclicking按钮给不同的div
- windows - 在命令行上创建一个 tar.xz 文件