一、什么是MongoDB?
MongoDB是由C++等语言开发的面向文档的数据库管理系统(文档是半结构化数据的一种,允许相同类的实体可以拥有不同的属性)。MongoDB使用类JSON格式BSON存储数据。
{
title:"MongoDB",
last_editor:"192.168.1.122",
last_modified:new Date("27/06/2011"),
body:"MongoDB introduction",
categories:["Database","NoSQL","BSON"],
revieved:false
}
上述示例是一个简单的BSON结构体,由多个键值对元素组成。
MongoDB属于NoSQL,在数据模型的概念上与关系型数据库有所区别。
可以发现:MongoDB没有JOIN这一操作,取而代之的是使用嵌入文档或引用的形式。
{
_id: <ObjectId1>,
name: "draveness",
books: [
{
_id: <ObjectId2>,
name: "MongoDB: The Definitive Guide"
},
{
_id: <ObjectId3>,
name: "High Performance MySQL"
}
]
}
上述示例中的books即为嵌入的子文档,作为对象存储在父文档中。
引用则是MongoDB中的标准化数据模型,文档间可以通过主键(_id)来进行链接。
二、MongoDB架构
MongoDB的架构和MySQL类似,默认的WiredTiger存储引擎所使用的默认数据结构也是B树,但WiredTiger所使用的B树与MySQL有所不同,且该引擎还支持使用LSM树结构。
三、WiredTiger存储结构
WiredTiger使用B树结构存储数据,但实际上是一种更类似B+树的结构。
如上是一个简化的结构图,内存中的B树分为三种节点,而磁盘中的数据则是紧凑的以Extent为单位排列。
在内存中,树的每个节点是一个页,根节点和内节点分别包含指向子页的页索引指针,叶节点包含键值对数据(WT_ROW array)和指向父页的指针,每条记录保留自己在页上的偏移量。
在磁盘上,每个页包含一个页头和块头以及真正的键值对数据,其中页头定义了页的类型、页中实际载荷数据的大小、页中记录条数等;块头定义页的checksum、块的磁盘寻址地址等。
WiredTiger通过一个块设备管理模块为页分配块,定位某一键值对数据时,先通过块的位置找到页,再通过页找到数据的偏移位置。
四、MongoDB查询优化
查询优化器是MongoDB的一部分,如果存在可用的索引,它会为给定查询选择一个最高效的索引。在为查询选择理性的索引时,优化查询器使用了一套相对简单的规则:
- 避免scanAndOrder,如果查询中包含排序,尝试使用索引进行排序。
- 通过有效的索引约束来满足所有字段--尝试对查询选择器里的字段使用索引。
- 如果查询包含范围查找或者排序,那么对于选择的索引,其中最后用到的键需能满足该范围查找或者排序。
如果某个索引能满足以上所有这些条件,那么它会被视为最佳索引并予以使用。要是有多个最佳索引,则任意选择一个。可以遵循这条经验:如果能为查询构建最优索引,查询优化器的工作能更轻松些。
参考文章
『浅入浅出』MongoDB 和 WiredTiger - 面向信仰编程draveness.me