mongodb底层存储和索引原理——本质是文档数据库,无表设计,同时wiredTiger存储引擎支持文档级别的锁,MMAPv1引擎基于mmap,二级索引(二级是文档的存储位置信息『文件id + 文件内offset 』)

简介:

MongoDB是面向文档的数据库管理系统DBMS(显然mongodb不是oracle那样的RDBMS,而仅仅是DBMS)。 想想一下MySQL中没有任何关系型数据库的表,而由JSON类型的对象组成数据模型的样子是如何的?

值得注意的是,MongoDB既不支持JOIN(连接)也不支持transaction(事务)。Significantly, MongoDB supports neither joins nor transactions.

但是请注意MongDB有着大量其他优良的特性,如二级索引、功能丰富的查询语言以及对每一个单个文档文件的原子写保证以及完全一致性的读取。

MongoDB 

rocks1

一、存储引擎(Storage)

    mongodb 3.0默认存储引擎为MMAPV1,还有一个新引擎wiredTiger可选,或许可以提高一定的性能。

    mongodb中有多个databases,每个database可以创建多个collections,collection是底层数据分区(partition)的单位,每个collection都有多个底层的数据文件组成。(参见下文data files存储原理)

    wiredTiger引擎:3.0新增引擎,官方宣称在read、insert和复杂的update下具有更高的性能。所以后续版本,我们建议使用wiredTiger。所有的write请求都基于“文档级别”的lock,因此多个客户端可以同时更新一个colleciton中的不同文档,这种更细颗粒度的lock,可以支撑更高的读写负载和并发量。因为对于production环境,更多的CPU可以有效提升wireTiger的性能,因为它是的IO是多线程的。wiredTiger不像MMAPV1引擎那样尽可能的耗尽内存,它可以通过在配置文件中指定“cacheSizeGB”参数设定引擎使用的内存量,此内存用于缓存工作集数据(索引、namespace,未提交的write,query缓冲等)。

    MMAPv1引擎:mongodb原生的存储引擎,比较简单,直接使用系统级的内存映射文件机制(memory mapped files),一直是mongodb的默认存储引擎,对于insert、read和in-place update(update不导致文档的size变大)性能较高;不过MMAPV1在lock的并发级别上,支持到collection级别,所以对于同一个collection同时只能有一个write操作执行,这一点相对于wiredTiger而言,在write并发性上就稍弱一些。对于production环境而言,较大的内存可以使此引擎更加高效,有效减少“page fault”频率,但是因为其并发级别的限制,多核CPU并不能使其受益。此引擎将不会使用到swap空间,但是对于wiredTiger而言需要一定的swap空间。(核心:对于大文件MAP操作,比较忌讳的就是在文件的中间修改数据,而且导致文件长度增长,这会涉及到索引引用的大面积调整)

    为了确保数据的安全性,mongodb将所有的变更操作写入journal并间歇性的持久到磁盘上,对于实际数据文件将延迟写入,和wiredTiger一样journal也是用于数据恢复。所有的记录在磁盘上连续存储,当一个document尺寸变大时,mongodb需要重新分配一个新的记录(旧的record标记删除,新的记record在文件尾部重新分配空间),这意味着mongodb同时还需要更新此文档的索引(指向新的record的offset),与in-place update相比,将消耗更多的时间和存储开支。由此可见,如果你的mongodb的使用场景中有大量的这种update,那么或许MMAPv1引擎并不太适合,同时也反映出如果document没有索引,是无法保证document在read中的顺序(即自然顺序)。3.0之后,mongodb默认采用“Power of 2 Sized Allocations”,所以每个document对应的record将有实际数据和一些padding组成,这padding可以允许document的尺寸在update时适度的增长,以最小化重新分配record的可能性。此外重新分配空间,也会导致磁盘碎片(旧的record空间)。

    Power of 2 Sized Allocations:默认情况下,MMAPv1中空间分配使用此策略,每个document的size是2的次幂,比如32、64、128、256...2MB,如果文档尺寸大于2MB,则空间为2MB的倍数(2M,4M,6M等)。这种策略有2种优势,首先那些删除或者update变大而产生的磁盘碎片空间(尺寸变大,意味着开辟新空间存储此document,旧的空间被mark为deleted)可以被其他insert重用,再者padding可以允许文档尺寸有限度的增长,而无需每次update变大都重新分配空间。此外,mongodb还提供了一个可选的“No padding Allocation”策略(即按照实际数据尺寸分配空间),如果你确信数据绝大多数情况下都是insert、in-place update,极少的delete,此策略将可以有效的节约磁盘空间,看起来数据更加紧凑,磁盘利用率也更高。

    内存映射存储引擎:MongoDB目前支持的存储引擎为内存映射引擎。当MongoDB启动的时候,会将所有的数据文件映射到内存中,然后操作系统会托管所有的磁盘操作。

 

    备注:mongodb 3.2+之后,默认的存储引擎为“wiredTiger”,大量优化了存储性能,建议升级到3.2+版本。

摘自:http://shift-alt-ctrl.iteye.com/blog/2255580

 

数据文件

在MongoDB的数据文件夹中(默认路径是/data/db)由构成数据库的所有文件。每一个数据库都包含一个.ns文件和一些数据文件,其中数据文件会随着数据量的增加而变多。所以如果有一个数据库名字叫做foo,那么构成foo这个数据库的文件就会由foo.ns,foo.0,foo.1,foo.2等等组成。数据文件每新增一次,大小都会是上一个数据文件的2倍,每个数据文件最大2G。这样的设计有利于防止数据量较小的数据库浪费过多的空间,同时又能保证数据量较大的数据库有相应的空间使用。

MongoDB会使用预分配方式来保证写入性能的稳定(这种方式可以使用–noprealloc关闭)。预分配在后台进行,并且每个预分配的文件都用0进行填充。这会让MongoDB始终保持额外的空间和空余的数据文件,从而避免了数据增长过快而带来的分配磁盘空间引起的阻塞。

 

数据存储及索引——更多可以看 http://lib.csdn.net/article/mongodb/53951 recordID本质上是位置信息是『文件id + 文件内offset 』

插入新文档时,MongoDB 会调用底层KV引擎存储文档内容,并生成一个 RecordId 的作为文档的位置信息标识,通过 RecordId 就能在底层KV引擎读取到文档的内容。

如果插入的集合包含索引(MongoDB的集合默认会有_id索引),针对每项索引,还会往底层KV引擎插入一个新的 key-value,key 是索引的字段内容,value 为插入文档时生成的 RecordId,这样就能快速根据索引找到文档的位置信息。

rocks2

如上图所示,集合包含{_id: 1}, {name: 1} 2个索引

  1. 用户插入文档时,底层引擎将文档内容存储,返回对应的位置信息,即 RecordId1
  2. 集合包含2个索引
    • 插入 {_id: ObjectId1} ==> RecordId1 的索引
    • 插入 {name: "rose"} ==> RecordId1 的索引

有了上述的数据,在根据_id访问时文档时 (根据其他索引字段类似)

  1. 根据文档的 _id 字段从底层KV引擎读取 RecordId
  2. 根据 RecordId 从底层KV引擎读取文档内容

摘自:https://toutiao.io/posts/9oxdop/preview 
















本文转自张昺华-sky博客园博客,原文链接:http://www.cnblogs.com/bonelee/p/6282072.html,如需转载请自行联系原作者

相关文章
|
存储 关系型数据库 MySQL
MySQL数据库索引的数据结构?
MySQL中默认使用B+tree索引,它是一种多路平衡搜索树,具有树高较低、检索速度快的特点。所有数据存储在叶子节点,非叶子节点仅作索引,且叶子节点形成双向链表,便于区间查询。
368 4
|
NoSQL MongoDB 微服务
微服务——MongoDB常用命令——文档的分页查询
本文介绍了文档分页查询的相关内容,包括统计查询、分页列表查询和排序查询。统计查询使用 `count()` 方法获取记录总数或按条件统计;分页查询通过 `limit()` 和 `skip()` 方法实现,控制返回和跳过的数据量;排序查询利用 `sort()` 方法,按指定字段升序(1)或降序(-1)排列。同时提示,`skip()`、`limit()` 和 `sort()` 的执行顺序与编写顺序无关,优先级为 `sort()` > `skip()` > `limit()`。
610 1
|
JSON NoSQL MongoDB
微服务——MongoDB常用命令——文档基本CRUD
本文介绍了MongoDB中文档的基本操作,包括插入、查询、更新和删除。单个文档插入使用`insert()`或`save()`方法,批量插入用`insertMany()`。查询所有文档用`find()`,条件查询可在`find()`中添加参数,投影查询控制返回字段。更新文档通过`update()`实现,支持覆盖修改、局部修改(使用`$set`)和批量修改。列值增长可用`$inc`实现。删除文档用`remove()`,需谨慎操作以免误删数据。此外,文档键值对有序,区分大小写,不能有重复键。
460 1
|
NoSQL 测试技术 MongoDB
微服务——MongoDB实战演练——根据上级ID查询文章评论的分页列表
本节介绍如何根据上级ID查询文章评论的分页列表,主要包括以下内容:(1)在CommentRepository中新增`findByParentid`方法,用于按父ID查询子评论分页列表;(2)在CommentService中新增`findCommentListPageByParentid`方法,封装分页逻辑;(3)提供JUnit测试用例,验证功能正确性;(4)使用Compass插入测试数据并执行测试,展示查询结果。通过这些步骤,实现对评论的高效分页查询。
336 0
|
缓存 NoSQL Redis
Redis原理—2.单机数据库的实现
本文概述了Redis数据库的核心结构和操作机制。
Redis原理—2.单机数据库的实现
|
存储 缓存 数据库
数据库索引采用B+树不采用B树的原因?
● B+树更便于遍历:由于B+树的数据都存储在叶子结点中,分支结点均为索引,方便扫库,只需要扫一遍叶子结点即可,但是B树因为其分支结点同样存储着数据,我们要找到具体的数据,需要进行一次中序遍历按序来扫,所以B+树更加适合在区间查询的情况,所以通常B+树用于数据库索引。 ● B+树的磁盘读写代价更低:B+树在内部节点上不包含数据信息,因此在内存页中能够存放更多的key。 数据存放的更加紧密,具有更好的空间局部性。因此访问叶子节点上关联的数据也具有更好的缓存命中率。 ● B+树的查询效率更加稳定:由于非终结点并不是最终指向文件内容的结点,而只是叶子结点中关键字的索引。所以任何关键字的查找必须走一条
|
存储 算法 关系型数据库
数据库主键与索引详解
本文介绍了主键与索引的核心特性及其区别。主键具有唯一标识、数量限制、存储类型和自动排序等特点,用于确保数据完整性和提升查询效率;而索引通过特殊数据结构(如B+树、哈希)优化查询速度,适用于不同场景。文章分析了主键与索引的优劣、适用场景及工作原理,并对比两者在唯一性、数量限制、功能定位等方面的差异,为数据库设计提供指导。
|
存储 监控 NoSQL
【赵渝强老师】MongoDB文档级别的并发控制
MongoDB使用WiredTiger存储引擎在文档级别进行并发控制,允许多个写操作同时修改不同文档,但对同一文档的修改需序列化执行。引擎采用乐观锁和意向锁机制处理冲突。通过视频讲解、插入大量文档示例及使用`mongotop`和`db.serverStatus()`命令,演示了如何监控MongoDB的锁信息和读写统计,展示了数据库和集合级别的写锁情况。
532 29
|
存储 NoSQL MongoDB
数据库数据恢复—MongoDB数据库迁移过程中丢失文件的数据恢复案例
某单位一台MongoDB数据库由于业务需求进行了数据迁移,数据库迁移后提示:“Windows无法启动MongoDB服务(位于 本地计算机 上)错误1067:进程意外终止。”
|
存储 缓存 数据库
数据库索引采用B+树不采用B树的原因?
B+树优化了数据存储和查询效率,数据仅存于叶子节点,便于区间查询和遍历,磁盘读写成本低,查询效率稳定,特别适合数据库索引及范围查询。
275 6

推荐镜像

更多