MongoDB 是一个高性能、可扩展的文档型数据库,它使用 C++ 语言编写,旨在为 Web 应用提供可扩展的高性能数据存储解决方案。MongoDB是一个开源的 NoSQL 数据库,它使用文档形式存储数据,相比传统关系型数据库,它更加灵活、可扩展和高性能。MongoDB的文档是以 JSON 格式存储的,这使得数据的存储和查询更加简洁和灵活。
MongoDB存储结构
MongoDB 的存储结构主要由如下三个单元组成:
- 文档(Document) :MongoDB 中最基本的单元,由 BSON 键值对(key-value)组成,类似于关系型数据库中的行(Row)。
json
{
"name":"suta",
"id": 123,
"city": hangzhou
}
- 集合(Collection) :一个集合可以包含多个文档,类似于关系型数据库中的表(Table)。
- 数据库(Database) :一个数据库中可以包含多个集合,可以在 MongoDB 中创建多个数据库,类似于关系型数据库中的数据库(Database)。
WiredTiger引擎
自 MongoDB 3.2 以后,默认的存储引擎为WiredTiger 存储引擎。
并发控制
WiredTiger 会对写入操作使用文档级并发控制,多个客户端可同时修改某一集合的不同文档。
- 对于大多数读取和写入操作,WiredTiger 均使用乐观并发控制。WiredTiger 仅在全局、数据库和集合级别使用意向锁。当存储引擎检测到两个操作之间存在冲突时,其中一个操作会引发写入冲突,从而导致 MongoDB 以透明方式重试该操作。
- WiredTiger 使用多版本并发控制 (MVCC)。在一个操作开始时,WiredTiger 会向该操作提供数据在该时间点的快照。快照提供的视图将与内存中数据保持一致。
MongoDB的数据结构
MongoDB默认使用B树存储数据,同时支持配置选择LSM树作为底层数据结构。
为何是B树不是B+树?
我们都知道,MySQL是使用B+树作为底层数据结构的,那么,MongoDB为何选择使用B树存储数据呢?
这个问题的理解可以从B+树与B树的差异出发进行思考:两者的本质差异是B+树只使用叶子结点存储数据,B树也会使用非叶子结点存储数据。
两者的差异决定了,当我们查询某个数据时,B树的搜索层数会更少,而当我们进行范围查找时,由于B+树中间节点没有源数据,其搜索步长就能更长,范围搜索的性能也会更佳。
虽然遍历数据的查询是相对常见的,但是 MongoDB 认为查询单个数据记录远比遍历数据更加常见,由于 B 树的非叶结点也可以存储数据,所以查询一条数据所需要的平均随机 IO 次数会比 B+ 树少,使用 B 树的 MongoDB 在类似场景中的查询速度就会比 MySQL 快。
这里并不是说 MongoDB 并不能对数据进行遍历,我们在 MongoDB 中也可以使用范围来查询一批满足对应条件的记录,只是需要的时间会比 MySQL 长一些。
为何默认没有选择LSM?
LSM 树是一个基于磁盘的数据结构,它设计的主要目的是为长期需要高频率写入操作的文件提供低成本的索引机制。无论是 B 树还是 B+ 树,向这些数据结构组成的索引文件中写入记录都需要执行的磁盘随机写,LSM 树的优化逻辑就是牺牲部分的读性能,将随机写转换成顺序写以优化数据的写入。
对于大多数的 OLTP 系统来说,系统的查询会是写的很多倍,所以 LSM 树在写入方面的优异表现也没有办法让它成为 MongoDB 默认的数据格式。
索引
B树的数据结构就表明MongoDB可以有着和MySQL类似的索引结构与设计,MongoDB 的复合索引也遵循左前缀原则。
另外,MongoDB提供了一个TTL索引过期机制,允许为每一个文档设置一个过期时间 expireAfterSeconds
,当一个文档达到预设的过期时间之后就会被删除。TTL 索引除了有 expireAfterSeconds
属性外,和普通索引一样。