值得注意的是,MongoDB既不支持JOIN(链接)也不支持transaction(事务)。Significantly, MongoDB supports neither joins nor transactions.mongodb
可是请注意MongDB有着大量其余优良的特性,如二级索引、功能丰富的查询语言以及对每个单个文档文件的原子写保证以及彻底一致性的读取。数据库
1、存储引擎(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操做,比较忌讳的就是在文件的中间修改数据,并且致使文件长度增加,这会涉及到索引引用的大面积调整)oracle
为了确保数据的安全性,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空间)。app
Power of 2 Sized Allocations:默认状况下,MMAPv1中空间分配使用此策略,每一个document的size是2的次幂,好比3二、6四、12八、256...2MB,若是文档尺寸大于2MB,则空间为2MB的倍数(2M,4M,6M等)。这种策略有2种优点,首先那些删除或者update变大而产生的磁盘碎片空间(尺寸变大,意味着开辟新空间存储此document,旧的空间被mark为deleted)能够被其余insert重用,再者padding能够容许文档尺寸有限度的增加,而无需每次update变大都从新分配空间。此外,mongodb还提供了一个可选的“No padding Allocation”策略(即按照实际数据尺寸分配空间),若是你确信数据绝大多数状况下都是insert、in-place update,极少的delete,此策略将能够有效的节约磁盘空间,看起来数据更加紧凑,磁盘利用率也更高。post
内存映射存储引擎: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始终保持额外的空间和空余的数据文件,从而避免了数据增加过快而带来的分配磁盘空间引发的阻塞。
『文件id + 文件内offset 』
插入新文档时,MongoDB 会调用底层KV引擎存储文档内容,并生成一个 RecordId 的做为文档的位置信息标识,经过 RecordId 就能在底层KV引擎读取到文档的内容。
若是插入的集合包含索引(MongoDB的集合默认会有_id索引),针对每项索引,还会往底层KV引擎插入一个新的 key-value,key 是索引的字段内容,value 为插入文档时生成的 RecordId,这样就能快速根据索引找到文档的位置信息。
如上图所示,集合包含{_id: 1}, {name: 1} 2个索引
有了上述的数据,在根据_id访问时文档时 (根据其余索引字段相似)
摘自:https://toutiao.io/posts/9oxdop/preview