我的一个聚合管道运行速度很慢。
该集合的名称为Document
,每个文档可以属于多个广告系列,并且位于五个雕像之一,即“a”到“e”。一小部分文档可能不属于任何文档,其campaigns
字段设置为null
。
示例文件:
{_id:id, campaigns:['c1', 'c2], status:'a', ...other fields...}
一些收集统计信息
如果状态位于['a','b','c']
,则查询的目标是计算每个广告系列每个广告系列的文档数量[
{$match:{campaigns:{$ne:null}, status:{$in:['a','b','c']}}},
{$unwind:'$campaigns'},
{$group:{_id:{campaign:'$campaigns', status:'$status'}, total:{$sum:1}}}
]
预计聚合几乎会影响整个系列。
如果没有索引,聚合将花费8 seconds
来完成。
我试图在
上创建一个索引{campaings:1, status:1}
解释计划显示已扫描索引,但聚合完成了near 11 seconds
。
索引包含聚合执行计数所需的所有字段。聚合是否应仅仅触及索引?该索引的大小仅为10MB。它怎么会慢?如果没有索引,还有其他任何调整查询的建议吗?
获胜计划显示:
{
"stage" : "FETCH",
"filter" : {"$not" : {"campaigns" : {"$eq" : null}}},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {"campaigns" : 1.0,"status" : 1.0},
"indexName" : "campaigns_1_status_1",
"isMultiKey" : true,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "forward",
"indexBounds" : {
"campaigns" : ["[MinKey, null)", "(null, MaxKey]"],
"status" : [ "[\"a\", \"a\"]", "[\"b\", \"b\"]", "[\"c\", \"c\"]"]
}
}
}
如果没有索引,获胜计划:
{
"stage" : "COLLSCAN",
"filter" : {
"$and":[
{"status": {"$in": ["a", "b", "c"]}},
{"$not" : {"campaigns": {"$eq" : null}}}
]
},
direction" : "forward"
}
根据@Kevin的要求,这里有一些关于其他所有索引的细节,大小以MB为单位。
"indexSizes" : {
"_id_" : 32,
"team_1" : 8, //Single value field of ObjectId
"created_time_1" : 16, //Document publish time in source system.
"parent_1" : 2, //_id of parent document.
"by.id_1" : 13, //_id of author from a different collection.
"feedids_1" : 8, //Array, _id of ETL jobs contributing to sync of this doc.
"init_-1" : 2, //Initial load time of the doc.
"campaigns_1" : 10, //Array, _id of campaigns
"last_fetch_-1" : 13, //Last sync time of the doc.
"categories_1" : 8, //Array, _id of document categories.
"status_1" : 8, //Status
"campaigns_1_status_1" : 10 //Combined index of campaign _id and status.
},
答案 0 :(得分:0)
在阅读MongoDB的文档后,我发现了这个:
不等式运算符$ ne不是很有选择性,因为它经常匹配索引的大部分。因此,在许多情况下,带有索引的$ ne查询可能不会比必须扫描集合中所有文档的$ ne查询执行得更好。另请参阅查询选择性。
使用$ type运算符查看一些不同的文章可能会解决问题。
您可以使用此查询:
db.data.aggregate([
{$match:{campaigns:{$type:2},status:{$in:["a","b","c"]}}},
{$unwind:'$campaigns'},
{$group:{_id:{campaign:'$campaigns', status:'$status'}, total:{$sum:1}}}])