MongoDB 聚合管道 $match order
Posted
技术标签:
【中文标题】MongoDB 聚合管道 $match order【英文标题】:MongoDB aggregation pipeline $match order 【发布时间】:2015-04-24 04:55:23 【问题描述】:我有 4 个分片的 MongoDB 集群。我的分片键是: client_id: 1, date: 1 使用过的集合有大约 50 M 的文档。
我将粘贴 1 个文档作为示例数据:
"_id" : ObjectId("54e069353e9104db470065e6"), "campaign_name" : "SC - Biker Planet", "adgroup_name" : "motociclista cerca", “client_id”:NumberLong(143), "adgroup_id" : NumberLong(28469), “campaign_id”:NumberLong(849), “设备”:“桌面”, “点击次数”:NumberLong(0), "conv" : NumberLong(0), “成本”:NumberLong(0), “印象数”:NumberLong(1), “日期”:ISODate(“2014-02-22T05:00:00.000Z”)现在,我已经安装了 MongoDB 3.0 RC9(带有强大的wiredTiger 存储引擎),我正在比较以下两个查询:
一)
db.google_raw_id.aggregate([ $匹配: client_id: 143, campaign_name: 'SC - 老年人约会', 日期: $gte: ISODate("2014-01-10T00:00:00.0Z"), $lte: ISODate("2015-01-10T00:00:00.0Z") , $组: _id: "$campaign_name", 成本:$sum: "$cost", 点击次数:$sum: "$clicks", 印象数:$sum: "$impressions" ])和
B)
db.google_raw_id.aggregate([ $匹配: client_id: 143, 日期: $gte: ISODate("2014-01-10T00:00:00.0Z"), $lte: ISODate("2015-01-10T00:00:00.0Z") , $组: _id: "$campaign_name", 成本:$sum: "$cost", 点击次数:$sum: "$clicks", 印象数:$sum: "$impressions" , $匹配: _id: 'SC - 老年人约会', ])执行查询 A 大约需要 0.35 秒,查询 B 大约需要 1.1 秒,它们都返回相同的结果。 正如您所看到的,它们之间的唯一区别是我将“campaign_name”过滤器从 $group 之前的 $match 移动到 $group 之后的 $match。
这是可以使用的方法吗,因为 shard key client_id, date 只有在第一个 $match 中没有其他过滤器时才能快速工作,或者我在配置中做错了什么?
更新
这里我解释了使用 MongoDB 聚合的查询 A 和 B http://pastebin.com/8fW7G6ty
在这里,我将查询 A 和 B 简化为使用 .find() http://pastebin.com/xa7UYBuh
我也有关于campaign_name 的索引,但如果在第一次匹配中使用campaign_name,聚合查询似乎会更慢,因为这不是分片键的一部分,这就是为什么Mongo 必须签入超过1 个分片的原因。
对我来说,这就是为什么查询 B 更快的合乎逻辑的解释。 在查询 B 中,Mongo 将结果缩减为更小的数据集,然后在该数据集上应用活动名称,因此它更快并且不会遍历其他分片。 只是我期待 MongoDB 可以自动解决这个问题:)
【问题讨论】:
这太令人惊讶了。只看它,B 天真地计算更多(天真地因为我对集合中的实际文档知之甚少,只知道它们的形状)。这两个管道应该总是产生相同的结果,所以如果后者更好,那么现在就使用它。如果您想检查为什么 B 更快,请发布两个查询的说明。您需要采取两个初始$match
阶段并将它们转换为查找查询并运行解释。
我已经用 2 个解释查询链接更新了我的帖子。我认为 B 应该只查询 1 个分片,因为分片键是 client_id, date 但是当使用campaign_name 时,它也会查询其他分片。至少这对我来说听起来合乎逻辑。所以我认为最好的方法是在第一个 $match 中只有分片键字段,然后再应用另一个 $match。
信息量很大,但我没有看到任何可以解释时间差异的东西。包含campaign_name
不会使它查询比它已经拥有的更多的分片 - 它仍然可以使用client_id
和date
定位查询。
信息量很大,但我没有看到任何可以解释时间差异的东西。包含campaign_name
不会让它查询比它已经拥有的更多的分片 - 它仍然可以使用client_id
和`date 来定位查询。
【参考方案1】:
A 更快,因为在第一次“匹配”之后,您已经对记录进行了分组(“匹配”之后的所有结果都具有相同的“活动名称”)。在“组”中只需要计算它们。
B 较慢,因为在第一次匹配后,您有 更多 个结果,并且在“组”中需要处理更多数据。换句话说,脚本将计算所有找到的广告系列的结果。
【讨论】:
以上是关于MongoDB 聚合管道 $match order的主要内容,如果未能解决你的问题,请参考以下文章
Mongodb 聚合管道优化 - $match 的 2 阶段
MongoDb 聚合 $match 错误:“参数必须是聚合管道运算符”
MongoDB $geoNear 聚合管道(使用查询选项和使用 $match 管道操作)给出不同的结果