场景
在MySQL中,通常会涉及多个表的一些操作,MongoDB也类似,有时需要将多个文档甚至是多个集合汇总到一起计算分析(比如求和、取最大值)并返回计算后的结果,这个过程被称为 聚合操作 。
根据官方文档介绍,我们可以使用聚合操作来:
- 将来自多个文档的值组合在一起。
- 对集合中的数据进行的一系列运算。
- 分析数据随时间的变化。
聚合
MongoDB 提供了两种执行聚合的方法:
- 聚合管道(Aggregation Pipeline):执行聚合操作的首选方法。
- 单一目的聚合方法(Single purpose aggregation methods):也就是单一作用的聚合函数比如 count()、distinct()、estimatedDocumentCount()。
绝大部分文章中还提到了 map-reduce 这种聚合方法。不过,从 MongoDB 5.0 开始,map-reduce 已经不被官方推荐使用了,替代方案是 聚合管道open in new window。聚合管道提供比 map-reduce 更好的性能和可用性。
MongoDB 聚合管道由多个阶段组成,每个阶段在文档通过管道时转换文档。每个阶段接收前一个阶段的输出,进一步处理数据,并将其作为输入数据发送到下一个阶段。
每个管道的工作流程是:
- 接受一系列原始数据文档
- 对这些文档进行一系列运算
- 结果文档输出给下一个阶段
常用阶段操作符:
- $match:匹配操作符,用于对文档集合进行筛选
- $project:投射操作符,用于重构每一个文档的字段,可以提取字段,重命名字段,甚至可以对原有字段进行操作后新增字段
- $sort:排序操作符,用于根据一个或多个字段对文档进行排序
- $limit:限制操作符,用于限制返回文档的数量
- $group:分组操作符,用于对文档集合进行分组
- $unwind:拆分操作符,用于将数组中的每一个值拆分为单独的文档
- $lookup:连接操作符,用于连接同一个数据库中另一个集合,并获取指定的文档,类似于 populate
举例
阶段操作符用于 db.collection.aggregate 方法里面,数组参数中的第一层。
db.collection.aggregate( [ { 阶段操作符:表述 }, { 阶段操作符:表述 }, ... ] )
下面是 MongoDB 官方文档中的一个例子:
db.orders.aggregate([# 第一阶段:$match阶段按status字段过滤文档,并将status等于"A"的文档传递到下一阶段。{ $match: { status: "A" } },# 第二阶段:$group阶段按cust_id字段将文档分组,以计算每个cust_id唯一值的金额总和。{ $group: { _id: "$cust_id", total: { $sum: "$amount" } } }
])
数据压缩
MongoDB将Bson作为数据存储结构,我们了解Json本身就已经算是一个冗余数据了,Bson在Json的基础上虽然做了二进制处理,但因为要记录内部字段的快速索引,所以存储成本和Json是差不多的。
借助 WiredTiger 存储引擎( MongoDB 3.2 后的默认存储引擎),MongoDB 支持对所有集合和索引进行压缩。压缩以额外的 CPU 为代价最大限度地减少存储使用。
默认情况下,WiredTiger 使用 Snappy 压缩算法(谷歌开源,旨在实现非常高的速度和合理的压缩,压缩比 3 ~ 5 倍)对所有集合使用块压缩,对所有索引使用前缀压缩。
除了 Snappy 之外,对于集合还有下面这些压缩算法:
- zlib:高度压缩算法,压缩比 5 ~ 7 倍
- Zstandard(简称 zstd):Facebook 开源的一种快速无损压缩算法,针对 zlib 级别的实时压缩场景和更好的压缩比,提供更高的压缩率和更低的 CPU 使用率,MongoDB 4.2 开始可用。
WiredTiger 日志也会被压缩,默认使用的也是 Snappy 压缩算法。如果日志记录小于或等于 128 字节,WiredTiger 不会压缩该记录。
snappy
https://github.com/google/snappy
Snappy 是一个压缩/解压缩库。它不追求最大程度的压缩,也不追求与任何其他压缩库的兼容性;相反,它追求极高的速度和合理的压缩。例如,与 zlib 的最快模式相比,Snappy 对大多数输入的处理速度要快一个数量级,但生成的压缩文件却要大 20% 到 100%。(Snappy 之前在一些 Google 演示等中被称为“Zippy”)
Snappy 具有以下属性:
- 快速:压缩速度达到 250 MB/秒及以上,无需汇编代码。
- 稳定:过去几年中,Snappy 在 Google 的生产环境中压缩和解压缩了数 PB 的数据。Snappy 比特流格式稳定,版本之间不会发生变化。
- 强大:Snappy 解压器的设计使得它在遇到损坏或恶意输入时也不会崩溃。
- 免费开源软件:Snappy 采用 BSD 类型的许可证。
Snappy 旨在提高速度。在 64 位模式下的 Core i7 处理器的单个核心上,它的压缩速度约为 250 MB/秒或更高,解压缩速度约为 500 MB/秒或更高。(这些数字针对的是我们基准测试套件中最慢的输入;其他输入要快得多。)在我们的测试中,Snappy 通常比同类算法(例如 LZO、LZF、QuickLZ 等)更快,同时实现相当的压缩率。
典型的压缩率(基于基准套件)对于纯文本约为 1.5-1.7 倍,对于 HTML 约为 2-4 倍,当然对于 JPEG、PNG 和其他已压缩数据约为 1.0 倍。zlib 在其最快模式下的类似数字分别为 2.6-2.8 倍、3-7 倍和 1.0 倍。更复杂的算法能够实现更高的压缩率,尽管通常以牺牲速度为代价。当然,压缩率会因输入的不同而有很大差异。
尽管 Snappy 的可移植性相当好,但它主要针对 64 位 x86 兼容处理器进行了优化,在其他环境中运行速度可能会更慢。特别是:
- Snappy 在多个地方使用 64 位操作来同时处理比其他方式更多的数据。
- Snappy 假设未对齐的 32 位和 64 位加载和存储很便宜。在某些平台上,必须使用单字节加载和存储来模拟这些操作,这会慢得多。