一.mongodb基本原理及使用
1.1.特点
- 基于分布式文件存储的开源数据库系统
- 原生支持数据分片集群存储(海量数据存储)
- 原生支持副本集群架构及Raft选举(高可用架构)
- 非关系式,数据存储结构松散并支持变更
MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。 MongoDB 文档类似于 JSON 对象的BSON格式存储(实质上是序列化的JSON,存储空间更小)。字段值可以包含其他文档,数组及文档数组。
1.2.使用场景
- 网站实时数据存储及展示
- 大规模日志数据存储
不适用场景:需要严格事务保证的系统(金融结算系统等)、需要复杂联表查询的存储结构。
一句话:大数据量、高拓展、能够把数据结构抽象到一个文档中表达的存储场景,可以考虑采用Mongo。
1.3.CRUD操作
- 插入文档
- 更新文档
-
获取文档
-
删除文档
1.4.索引
mongodb的索引使用B树组织,默认以_id建立数据索引,并且也支持索引覆盖特性。
mongodb索引支持单一索引、复合索引来建立B树索引。除了基本的数值及字符串型索引外,mongodb还支持以下特殊类型索引:
1.4.1.文本索引
文本索引用以支持对字符串内容的文本搜索查询。text索引可以包含任何值为字符串或字符串元素数组的字段上。对文本索引字段的写入前会进行分词并建立倒排索引。(注意,mongodb默认支持英文方式的分词,对于中文分词不友好,需要借助其他分词插件)
-
对reviews文档中的comments字段建立文本索引
db.reviews.createIndex( { comments: “text” } ) -
对reviews文档中的comments及subject字段分别建立文本索引
db.reviews.createIndex(
{
subject: "text",
comments: "text"
}
)
- 建立文本索引并指定分词语言
db.quotes.createIndex(
{ content : "text" },
{ default_language: "chinese" }
)
- 指定各索引字段权重
db.blog.createIndex(
{
content: "text",
keywords: "text",
about: "text"
},
{
weights: {
content: 10,
keywords: 5
},
name: "TextIndex"
}
)
- 后台异步建立索引:避免阻塞文档操作
db.quotes.createIndex(
{ content : "text" },
{ background: true }
)
1.4.2.地理位置索引
2dsphere索引支持计算类似地球的球体上的几何形状的查询。2dsphere索引支持所有MongoDB地理空间查询:包含、相交和邻近度查询。
- 插入GeoJSON Point形式的地理位置文档
db.places.insert(
{
loc : { type: "Point", coordinates: [ -73.97, 40.77 ] },
name: "Central Park",
category : "Parks"
}
)
db.places.insert(
{
loc : { type: "Point", coordinates: [ -73.88, 40.78 ] },
name: "La Guardia Airport",
category : "Airport"
}
)
- 创建2dsphere索引
db.places.createIndex( { loc : "2dsphere" } )
- 查找位于某区域内的文档
db.places.find( { loc : -- 位置
{ $geoWithin : -- 位于区域内
{ $geometry :
{ type : "Polygon" , -- 区域
coordinates : [ [ -- 四点区域
[ 0 , 0 ] ,
[ 3 , 6 ] ,
[ 6 , 1 ] ,
[ 0 , 0 ]
] ]
} } } } )
- 查找据某位置内指定距离内的文档
db. places.find( { loc : -- 位置
{ $near : -- 附近区域内
{ $geometry :
{ type : "Point" , -- 位置
coordinates : [ 1, 2 ] } ,
$maxDistance : 100 -- 最远距离100m
} } } )
二.mongodb体系结构原理
2.1.mongodb体系结构
数据库-集合-文档
数据库-表-行
2.2.WiredTiger索引
WiredTiger是一个优秀的单机数据库存储引擎,支持B树索引及LSM树索引、事务等特性,被mongodb 3.2之后版本默认使用作为存储引擎。
索引存储结构一般有两种:
- B树:传统的SQL数据库通常使用B树来存储索引数据(mongodb默认情况下也使用B树来存储索引)
- LSM树:es、lucene、hbase、rocksdb等使用LSM树(日志合并树)来实现索引
典型的B树结构(读快写慢):
- 根节点至少有两个子节点
- 每个节点有M-1个key,并且以升序排列
- 位于M-1和M key的子节点的值位于M-1 和M key对应的Value之间
- 其它节点至少有M/2个子节点
- 所有叶子结点位于同一层;
B+树是B树的变种,差异在于叶子节点才包含数据信息,并且叶子节点被双向链表连接方便范围遍历)
典型的LSM树结构(读慢写快):
LSM树的设计思想非常朴素:将对数据的修改增量保持在内存中,达到指定的大小限制后将这些修改操作批量写入磁盘,不过读取的时候稍微麻烦,需要合并磁盘中历史数据和内存中最近修改操作,所以写入性能大大提升,读取时可能需要先看是否命中内存,否则需要访问较多的磁盘文件。
LSM树原理把一棵大树拆分成N棵小树,它首先写入内存中,随着小树越来越大,内存中的小树会flush到磁盘中,磁盘中的树定期可以做merge操作,合并成一棵大树,以优化读性能。
本质上来说,LSM树把对磁盘的随机写入优化为了顺序写入。
2.3.副本集原理(高可用)
2.4.分片集群原理(高拓展)
2.5.如何优化查询性能
-
先开启慢查询分析器Profiler
db.setProfilingLevel(1, 1000) – 查询时间大于1000ms就记录下来 -
查看慢查询日志,定位到具体查询语句
db.system.profile.find() -
对各个涉及到的集合进行索引建立
三.mongodb常见问题
3.1.查询分析器Profiler的作用
MongoDB中包括了一个可以显示数据库中每个操作性能特点的数据库分析器。通过这个分析器你可以找到比预期慢的查询(或写操作);利用这一信息,比如,可以确定是否需要添加索引。
3.2.更新操作立刻fsync到磁盘吗
不会,磁盘写操作默认是延迟执行的。
写操作可能在两三秒(默认在60秒内)后到达磁盘。例如,如果一秒内数据库收到一千个对一个对象递增的操作,仅刷新磁盘一次。(注意,尽管fsync选项在命令行和经过getLastError_old是有效的)
3.3.为什么数据文件如此庞大
MongoDB会积极的预分配预留空间来防止文件系统碎片。
3.4.什么是master或primary
副本集架构中,master及primary是当前备份集群(replica set)中负责处理所有写入操作的主节点。在一个备份集群中,当失效备援(failover)事件发生时,一个另外的slave成员会通过Raft选举为变成primary。
3.5.什么是secondary或slave?
副本集架构中,Seconday从当前的primary上复制相应的操作。它是通过跟踪复制oplog(local.oplog.rs)做到的。
3.6.分片(sharding)和复制(replication)是怎样工作的
每一个分片(shard)是一个分区数据的逻辑集合。分片可能由单一服务器或者集群组成,我们推荐为每一个分片(shard)使用集群。
3.7.当更新一个正在被迁移的块(Chunk)上的文档时会发生什么
更新操作会立即发生在旧的块(Chunk)上,然后更改才会在所有权转移前复制到新的分片上。
3.8.MongoDB在A:{B,C}上建立索引,查询A:{B,C}和A:{C,B}都会使用索引吗
不会,查询时需要以联合索引建立顺序为准,所以只会在A:{B,C}上使用索引。
3.9.如何理解MongoDB中的GridFS机制,MongoDB为何使用GridFS来存储文件?
GridFS是一种将大型文件存储在MongoDB中的文件规范。使用GridFS可以将大文件分隔成多个小文档存放,这样我们能够有效的保存大文档,而且解决了BSON对象有限制的问题。
3.10.什么是NoSQL数据库?NoSQL和RDBMS有什么区别?在哪些情况下使用和不使用NoSQL数据库?
NoSQL是非关系型数据库,NoSQL = Not Only SQL。
关系型数据库采用的结构化的数据,NoSQL采用的是键值对的方式存储数据。
在处理非结构化/半结构化的大数据时;在水平方向上进行扩展时;随时应对动态增加的数据项时可以优先考虑使用NoSQL数据库。
在考虑数据库的成熟度;支持;分析和商业智能;管理及专业性等问题时,应优先考虑关系型数据库。
3.11.MongoDB的优势有哪些
- 面向文档的存储:以 JSON 格式的文档保存数据。
- 任何属性都可以建立索引。
- 复制以及高可扩展性。
- 自动分片。
- 丰富的查询功能。
- 快速的即时更新。
- 来自 MongoDB 的专业支持。
3.12.什么是集合
集合就是一组 MongoDB 文档。它相当于关系型数据库(RDBMS)中的表这种概念。集合位于单独的一个数据库中。一个集合内的多个文档可以有多个不同的字段。一般来说,集合中的文档都有着相同或相关的目的。
3.13.什么是文档
文档由一组key value组成。文档是动态模式,这意味着同一集合里的文档不需要有相同的字段和结构。在关系型数据库中table中的每一条记录相当于MongoDB中的一个文档。
3.14.什么是mongod
mongod是处理MongoDB系统的主要进程。它处理数据请求,管理数据存储,和执行后台管理操作。当我们运行mongod命令意味着正在启动MongoDB进程,并且在后台运行。
3.15.非关系型数据库有哪些类型
- Key-Value 存储:Redis
- 图存储:Neo4J
- 文档存储:MongoDB
- 基于列存储:Cassandra、HBase
3.16.在哪些场景使用MongoDB
- 大数据
- 内容管理系统
- 移动端Apps
- 数据管理
3.17.MongoDB中的分片是什么意思
分片是将数据水平切分到不同的物理节点。当应用数据越来越大的时候,数据量也会越来越大。当数据量增长时,单台机器有可能无法存储数据或可接受的读取写入吞吐量。利用分片技术可以添加更多的机器来应对数据量增加以及读写操作的要求。
3.18.什么是复制
复制是将数据同步到多个服务器的过程,通过多个数据副本存储到多个服务器上增加数据可用性。复制可以保障数据的安全性,灾难恢复,无需停机维护(如备份,重建索引,压缩),分布式读取数据。
3.19.ObjectID由哪些部分组成
一共有四部分组成:
- 时间戳
- 客户端ID
- 客户进程ID
- 增量计数器
_id是一个 12 字节长的十六进制数,它保证了每一个文档的唯一性。在插入文档时,需要提供 _id 。如果你不提供,那么 MongoDB 就会为每一文档提供一个唯一的 id。 _id 的头 4 个字节代表的是当前的时间戳,接着的后 3 个字节表示的是机器 id 号,接着的 2 个字节表示MongoDB 服务器进程 id,最后的 3 个字节代表递增值。
3.20.如何使用"AND"或"OR"条件循环查询集合中的文档
在 find() 方法中,如果传入多个键,并用逗号( , )分隔它们,那么 MongoDB 会把它看成是AND条件。
db.mycol.find({key1:value1, key2:value2}).pretty()
若基于OR条件来查询文档,可以使用关键字$or。
db.mycol.find(
{
$or: [
{key1: value1}, {key2:value2}
]
}
).pretty()
3.21.在MongoDB中如何排序
MongoDB 中的文档排序是通过 sort() 方法来实现的。 sort() 方法可以通过一些参数来指定要进行排序的字段,并使用 1 和 -1 来指定排序方式,其中 1 表示升序,而 -1 表示降序。
db.connectionName.find({key:value}).sort({columnName:1})
3.22.什么是聚合
聚合操作能够处理数据记录并返回计算结果。聚合操作能将多个文档中的值组合起来,对成组数据执行各种操作,返回单一的结果。它相当于 SQL 中的 count(*) 组合 group by。对于 MongoDB 中的聚合操作,应该使用 aggregate() 方法。
db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION)