Mongodb聚合$group阶段耗时较长
Posted
技术标签:
【中文标题】Mongodb聚合$group阶段耗时较长【英文标题】:Mongodb aggregate $group stage takes a long time 【发布时间】:2019-10-24 23:51:27 【问题描述】:我正在练习如何使用 MongoDB 聚合,但它们似乎需要很长时间(运行时间)。
每当我使用$group
时,似乎都会发生问题。所有其他查询都运行良好。
我有一些1.3
百万虚拟文档需要执行两个基本操作:获取IP地址的计数和唯一 IP 地址。
我的架构看起来像这样:
"_id":"5da51af103eb566faee6b8b4",
"ip_address":"...",
"country":"CL",
"browser":
"user_agent":...",
运行一个基本的$group
查询平均需要大约12
s,这太慢了。
我做了一些研究,有人建议在ip_addresses
上创建一个索引。这似乎减慢了速度,因为查询现在需要13-15
s。
我使用 MongoDB,我正在运行的 查询 如下所示:
visitorsModel.aggregate([
'$group':
'_id': '$ip_address',
'count':
'$sum': 1
]).allowDiskUse(true)
.exec(function (err, docs)
if (err) throw err;
return res.send(
uniqueCount: docs.length
)
)
感谢任何帮助。
编辑:我忘了说,有人说可能是硬件问题?如果有帮助,我将在核心 i5、8GB RAM 笔记本电脑上运行查询。
编辑 2:查询计划:
"stages" : [
"$cursor" :
"query" :
,
"fields" :
"ip_address" : 1,
"_id" : 0
,
"queryPlanner" :
"plannerVersion" : 1,
"namespace" : "metrics.visitors",
"indexFilterSet" : false,
"parsedQuery" :
,
"winningPlan" :
"stage" : "COLLSCAN",
"direction" : "forward"
,
"rejectedPlans" : [ ]
,
"executionStats" :
"executionSuccess" : true,
"nReturned" : 1387324,
"executionTimeMillis" : 7671,
"totalKeysExamined" : 0,
"totalDocsExamined" : 1387324,
"executionStages" :
"stage" : "COLLSCAN",
"nReturned" : 1387324,
"executionTimeMillisEstimate" : 9,
"works" : 1387326,
"advanced" : 1387324,
"needTime" : 1,
"needYield" : 0,
"saveState" : 10930,
"restoreState" : 10930,
"isEOF" : 1,
"invalidates" : 0,
"direction" : "forward",
"docsExamined" : 1387324
,
"$group" :
"_id" : "$ip_address",
"count" :
"$sum" :
"$const" : 1
],
"ok" : 1
【问题讨论】:
您查看查询执行统计信息了吗?请分享它们 @AmitPhaltankar 将其添加到原始问题中 查询计划显示 COLLSCAN,查询性能可以受益于索引。集合上是否定义了任何索引? 你能说出你为什么使用allowDiskUse
和exec
吗?
另见:(1) Aggregation, (2) db.collection.aggregate(), 和 $group (aggregation)。
【参考方案1】:
这是有关使用 $group
聚合阶段的一些信息,如果它使用索引,它的局限性以及可以尝试克服这些问题的方法。
1. $group 阶段不使用索引: Mongodb Aggregation: Does $group use index?
2. $group 运算符和内存:
$group
阶段的 RAM 限制为 100 兆字节。默认情况下,如果 阶段超过此限制,$group
返回错误。允许 处理大型数据集,将allowDiskUse
选项设置为true。 此标志允许 $group 操作写入临时文件。
见MongoDb docs on $group Operator and Memory
3.使用 $group 和 Count 的示例:
一个名为cities
的集合:
"_id" : 1, "city" : "Bangalore", "country" : "India"
"_id" : 2, "city" : "New York", "country" : "United States"
"_id" : 3, "city" : "Canberra", "country" : "Australia"
"_id" : 4, "city" : "Hyderabad", "country" : "India"
"_id" : 5, "city" : "Chicago", "country" : "United States"
"_id" : 6, "city" : "Amritsar", "country" : "India"
"_id" : 7, "city" : "Ankara", "country" : "Turkey"
"_id" : 8, "city" : "Sydney", "country" : "Australia"
"_id" : 9, "city" : "Srinagar", "country" : "India"
"_id" : 10, "city" : "San Francisco", "country" : "United States"
查询集合以按国家统计城市:
db.cities.aggregate( [
$group: _id: "$country", cityCount: $sum: 1 ,
$project: country: "$_id", _id: 0, cityCount: 1
] )
结果:
"cityCount" : 3, "country" : "United States"
"cityCount" : 1, "country" : "Turkey"
"cityCount" : 2, "country" : "Australia"
"cityCount" : 4, "country" : "India"
4.使用 allowDiskUse 选项:
db.cities.aggregate( [
$group: _id: "$country", cityCount: $sum: 1 ,
$project: country: "$_id", _id: 0, cityCount: 1
], allowDiskUse : true )
注意,在这种情况下,它对查询性能或输出没有影响。这只是为了展示用法。
5.一些尝试的选项(建议):
您可以尝试一些方法以获得一些结果(仅供试用):
使用$limit
阶段并限制处理的文档数量和
看看结果如何。例如,您可以尝试 $limit: 1000
。
注意这个阶段需要在$group
阶段之前。
您还可以在$group
之前使用$match
、$project
阶段
阶段来控制输入的shape和size。这可能
返回结果(而不是错误)。
[编辑添加]
Distinct 和 Count 的注意事项:
使用相同的 cities
集合 - 要获取唯一的国家/地区及其计数,您可以尝试使用聚合阶段 $count
和 $group
,如以下两个查询所示。
区别:
db.cities.aggregate( [
$match: country: $exists: true ,
$group: _id: "$country" ,
$project: country: "$_id", _id: 0
] )
结果:
"country" : "United States"
"country" : "Turkey"
"country" : "India"
"country" : "Australia"
要将上述结果作为具有唯一值数组的单个文档获取,请使用$addToSet
operator:
db.cities.aggregate( [
$match: country: $exists: true ,
$group: _id: null, uniqueCountries: $addToSet: "$country" ,
$project: _id: 0 ,
] )
结果: "uniqueCountries" : [ "United States", "Turkey", "India", "Australia" ]
计数:
db.cities.aggregate( [
$match: country: $exists: true ,
$group: _id: "$country" ,
$project: country: "$_id", _id: 0 ,
$count: "uniqueCountryCount"
] )
结果: "uniqueCountryCount" : 4
在上述查询中,$match
阶段用于过滤不存在或为空的country
field 的任何文档。 $project
阶段重塑结果文档。
MongoDB 查询语言:
请注意,当使用 MongoDB 查询语言 命令时,这两个查询会得到相似的结果:db.collection.distinct("country")
和 db.cities.distinct("country").length
(注意 distinct
返回一个数组)。
【讨论】:
【参考方案2】:你可以创建索引
db.collectionname.createIndex( ip_address: "text" )
试试这个,它更快。 我想它会对你有所帮助。
【讨论】:
集合已有索引。运行此返回..."note" : "all indexes already exist"
...
你取的ip_address的数据类型是什么?以上是关于Mongodb聚合$group阶段耗时较长的主要内容,如果未能解决你的问题,请参考以下文章