MongoDB
什么是MongoDB
MongoDB 是一个基于 分布式文件存储 的开源 NoSQL 数据库系统,由 C++ 编写的。MongoDB 提供了 面向文档 的存储方式,操作起来比较简单和容易,支持“无模式”的数据建模,可以存储比较复杂的数据类型,是一款非常流行的 文档类型数据库 。
在高负载的情况下,MongoDB 天然支持水平扩展和高可用,可以很方便地添加更多的节点/实例,以保证服务性能和可用性。在许多场景下,MongoDB 可以用于代替传统的关系型数据库或键/值存储方式,皆在为 Web 应用提供可扩展的高可用高性能数据存储解决方案。
存储结构
MongoDB 的存储结构区别于传统的关系型数据库,主要由如下三个单元组成:
- 文档(Document) :MongoDB 中最基本的单元,由 BSON 键值对(key-value)组成,类似于关系型数据库中的行(Row)。
- 集合(Collection) :一个集合可以包含多个文档,类似于关系型数据库中的表(Table)。
- 数据库(Database) :一个数据库中可以包含多个集合,可以在 MongoDB 中创建多个数据库,类似于关系型数据库中的数据库(Database)。
也就是说,MongoDB 将数据记录存储为文档 (更具体来说是BSON),这些文档在集合中聚集在一起,数据库中存储一个或多个文档集合。
SQL 与 MongoDB 常见术语对比 :
SQL | MongoDB |
---|---|
表(Table) | 集合(Collection) |
行(Row) | 文档(Document) |
列(Col) | 字段(Field) |
主键(Primary Key) | 对象 ID(Objectid) |
索引(Index) | 索引(Index) |
嵌套表(Embeded Table) | 嵌入式文档(Embeded Document) |
数组(Array) | 数组(Array) |
文档
MongoDB 中的记录就是一个 BSON 文档,它是由键值对组成的数据结构,类似于 JSON 对象,是 MongoDB 中的基本数据单元。字段的值可能包括其他文档、数组和文档数组。
BSON vs JSON
集合
MongoDB 集合存在于数据库中,没有固定的结构,也就是 无模式 的,这意味着可以往集合插入不同格式和类型的数据。不过,通常情况下,插入集合中的数据都会有一定的关联性。
集合不需要事先创建,当第一个文档插入或者第一个索引创建时,如果该集合不存在,则会创建一个新的集合。
数据库
数据库用于存储所有集合,而集合又用于存储所有文档。一个 MongoDB 中可以创建多个数据库,每一个数据库都有自己的集合和权限。
MongoDB 预留了几个特殊的数据库。
- admin : admin 数据库主要是保存 root 用户和角色。例如,system.users 表存储用户,system.roles 表存储角色。一般不建议用户直接操作这个数据库。将一个用户添加到这个数据库,且使它拥有 admin 库上的名为 dbAdminAnyDatabase 的角色权限,这个用户自动继承所有数据库的权限。一些特定的服务器端命令也只能从这个数据库运行,比如关闭服务器。
- local : local 数据库是不会被复制到其他分片的,因此可以用来存储本地单台服务器的任意 collection。一般不建议用户直接使用 local 库存储任何数据,也不建议进行 CRUD 操作,因为数据无法被正常备份与恢复。
- config : 当 MongoDB 使用分片设置时,config 数据库可用来保存分片的相关信息。
- test : 默认创建的测试库,连接服务时,如果不指定连接的具体数据库,默认就会连接到 test 数据库。
存储引擎
存储引擎(Storage Engine)是数据库的核心组件,负责管理数据在内存和磁盘中的存储方式。
与 MySQL 一样,MongoDB 采用的也是 插件式的存储引擎架构 ,支持不同类型的存储引擎,不同的存储引擎解决不同场景的问题。在创建数据库或集合时,可以指定存储引擎。
MMAPV1
WiredTiger 存储引擎
自 MongoDB 3.2 以后,默认的存储引擎为 WiredTiger 存储引擎 。非常适合大多数工作负载,建议用于新部署。WiredTiger 提供文档级并发模型、检查点和数据压缩等功能。
MongoDB 在使用WiredTiger 作为存储引擎时,默认使用的是 B 树,此外,WiredTiger 还支持 LSM树作为存储结构。
为什么是B而不是B+
MongoDB 对于遍历数据的需求没有关系型数据库那么强,它追求的是读写单个记录的性能;
MySQL 中使用 B+ 树是因为 B+ 树只有叶节点会存储数据,将树中的每一个叶节点通过指针连接起来就能实现顺序遍历,而遍历数据在关系型数据库中非常常见.
MongoDB 和 MySQL 在多个不同数据结构之间选择的最终目的就是减少查询需要的随机 IO 次数,MySQL 认为遍历数据的查询是常见的,所以它选择 B+ 树作为底层数据结构,而舍弃了通过非叶节点存储数据这一特性,但是 MongoDB 认为查询单个数据记录远比遍历数据更加常见,由于 B 树的非叶结点也可以存储数据,所以查询一条数据所需要的平均随机 IO 次数会比 B+ 树少,使用 B 树的 MongoDB 在类似场景中的查询速度就会比 MySQL 快。
In-Memory 存储引擎
In-Memory 存储引擎在 MongoDB Enterprise 中可用。它不是将文档存储在磁盘上,而是将它们保留在内存中以获得更可预测的数据延迟。
聚合操作
实际项目中,我们经常需要将多个文档甚至是多个集合汇总到一起计算分析(比如求和、取最大值)并返回计算后的结果,这个过程被称为 聚合操作 。
根据官方文档介绍,我们可以使用聚合操作来:
- 将来自多个文档的值组合在一起。
- 对集合中的数据进行的一系列运算。
- 分析数据随时间的变化
MongoDB 提供了两种执行聚合的方法:
- 聚合管道(Aggregation Pipeline) :执行聚合操作的首选方法。
- 单一目的聚合方法(Single purpose aggregation methods) :也就是单一作用的聚合函数比如
count()
、distinct()
、estimatedDocumentCount()
。
事务
不同于其它NOSQL数据库,MongoDB是支持ACID的,其事务和关系型数据库的事务概念相似;
数据压缩
借助 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 不会压缩该记录。