这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战
MongoDB
NoSQL 列存储Hbase 键值 Redis 图像 Neo4j 文档 Mongodb
安装
tar -zxvf MongoDB-linux-x86_64-4.1.3.tgz
./bin/mongod -f mongo.conf
# 配置:
dbPath=/data/mongo/ # 数据库目录
port=27017 # 监听端口
bind_ip=0.0.0.0 # 监听IP
fork=true # 是否以后台启动的方式登录
logpath=/data/mongo/MongoDB.log #日志路径
logappend=true # 是否追加日志
auth=false # 是否开启用户密码登录
# 连接
./bin/mongo --host= --port=
命令
数据库
show dbs;
use 数据库名; #没有的话则创建
db.createCollection("集合名")
show tables;
show collections;
db.集合名.drop();
db.dropDatabase();
集合
db.集合名.insert(文档)
db.集合名.insert([文档], [文档])
db.test.insert({name:"张", birthday: new ISODate("2000-07-01")})
_id类型是ObjectId类型, 是一个12字节BSON类型的数据,格式是
前4位是时间戳, 接下来3位是机器标识码, 接下来2位字节是PID, 接下来三个字节是随机数。
可以用ObjectId("对象ID字符串").getTimeStamp()
db.集合名.find(条件)
| 操作 | 格式 |
|---|---|
| 等于 | {key:value} |
| 大于 | {key: {$gt: value}} |
| 大于等于 | {key: {$gte: value}} |
| 不等于 | {key: {$ne: value}} |
| and | {key1:value1, key2:value2} |
| or | {$or:[{key1:value1}, {key2:value2}] |
| not | {key:{not:{操作符:value}} |
db.集合名.find({条件}).sort({排序字段:排序方式})).skip(跳过的行数).limit(一页显示多少数据)
$set: 设置字段值
$unset: 删除指定字段
$inc: 自增
db.集合名.update(
<query>, # update查询条件
<update>, # $set
{
upsert: <boolean>, # 可选, 不存在就插入,默认false
multi: <boolean>, # 默认false, 只更新找到的第一条记录
writeConcern: <document> # 可选, 指定mogod对写操作的回执行为,比如写行为是否需要确认
}
)
db.集合名.update({条件}, {$set: {key,value}}, {multi:true})
writeConcern 包括以下字段: { w: <value>, j: <boolean>, wtimeout: <number> }
w:指定写操作传播到的成员数量 比如:
w=1(默认):则要求得到写操作已经传播到独立的Mongod实例或副本集的primary成员的确认
w=0:则不要求确认写操作,可能会返回socket exceptions和 networking errors
w="majority":要求得到写操作已经传播到大多数具有存储数据具有投票的(data-bearing voting )成员(也就是 members[n].votes 值大于0的成员)的确认
j:要求得到Mongodb的写操作已经写到硬盘日志的确认 比如:
j=true:要求得到Mongodb(w指定的实例个数)的写操作已经写到硬盘日志的确认。j=true本身并不保证因为副本集故障而不会回滚。
wtimeout:指定write concern的时间限制,只适用于w>1的情况 wtimeout在超过指定时间后写操作会返回error,即使写操作最后执行成功,当这些写操作返回时, MongoDB不会撤消在wtimeout时间限制之前执行成功的数据修改。 如果未指定wtimeout选项且未指定write concern级别,则写入操作将无限期阻止。 指定wtimeout值 为0等同于没有wtimeout选项
db.collection.remove( <query>, { justOne: <boolean>, writeConcern: <document> } )
参数说明:
query :(可选)删除的文档的条件。
justOne : (可选)如果设为 true 或 1,则只删除一个文档,如果不设置该参数,或使用默认值 false,则删除所有匹配条件的文档。
writeConcern :(可选)用来指定mongod对写操作的回执行为。
聚合
-
单目聚合操作
count(), distinct()
db.test.distinct("city") -
聚合管道
db.test.aggregate([{$group:{_id:"$city", city_count:{"$sum:1"}}}]) db.test.aggregate([{$group:{_id:"$city", city_avg:{"$avg:$salary"}}}]) db.test.aggregate([{$group:{_id:"$city", city_name:{"$push:$city"}}}])表达式 描述 $sum 总和 $avg 平均值 $min 最小值 $max 最大值 $push 在结果文档中插入值到一个数组中 $addToSet 在结果文档中插入值到一个数组,值不重复 $first 获取第一个 $last 获取最后一个 管道操作
$group : 分组
$project: 修改文档结构名
$match: 过滤数据
$limit: 限制返回数
$skip: 跳过
$sort: 排序
$geoNear: 接近某个位置的有序文档
-
MapReduce
能够在多台Server上并行执行复杂的聚合逻辑。
db.test.mapReduce( function() {emit(this.city, this.salary);},# map function(key, value){return Array.avg(value)},# reduce { query:{salary:{$gt: 1000}}, out: "cityAvgsal", finalize: function(key, value){ return value +5000; } } )out: 统计结果存放集合
query: 条件
sort: 发往map前排序
limit: map文档上限
finalize: 对reduce结果进行修改
verbose: 是否包括时间信息,默认false
索引
单键索引:
支持所有类型的单个字段索引,索引排序顺序无关紧要, 可以在任一方向读取索引。
db.test.createIndex({name:1}, {background: true})
db.test.getIndexes()
db.test.totalIndexSize()
db.test.reIndex()
db.test.dropIndex("name")
db.test.dropIndexes()
过期索引TTL
可以支持文档在一定时间后自动删除,目前TTL只能在单字段上建立,并且必须是日期类型。
db.test.createIndex({name:1}, {expireAfterSeconds: 31})
复合索引
db.test.createIndex({name:1, score:-1})
多键索引
针对属性包数组, 支持对数组中element创建索引, 支持strings, numbers和nested documents
db.test.createIndex({ratings:1})
地理空间索引
2dsphere 用于存储和查找球面上的点
2d 索引用来存储和查找平面上的点
全文索引
提供了针对string内容的文本查询。 一个集合最多支持一个Text Index
db.test.createIndex({"name":"text"})
db.test.find({"$text":{"$search": "coffee"}})
哈希索引
针对属性的哈希值进行索引
db.test.createIndex({"name":"hashed"})
索引管理
explain 接收不同的参数
- queryPlanner
- executionStats
- allPlansExecution
慢查询
-
开启内置的查询分析器
db.setProfifilingLevel(n,m),n的取值可选0,1,2
- 0表示不记录
- 表示记录慢速操作,如果值为1,m必须赋值单位为ms,用于定义慢速查询时间的阈值
- 表示记录所有的读写操作
-
查询监控结果
db.system.profile.find().sort({millis:-1}).limit(3) -
解读explain结果 确定是否缺少索引
索引底层实现
MongoDB使用B-树,所有节点都有Data域,只要找到指定索引就可以进行访问,单次查询从结构上来看要快于MySql。
B-树的特点:
-
多路 非二叉树
-
每个节点 既保存数据 又保存索引
-
搜索时 相当于二分查找
B+ 树的特点:
-
多路非二叉
-
只有叶子节点保存数据
-
搜索时 也相当于二分查找
-
增加了 相邻节点指针
从上面我们可以看出最核心的区别主要有俩,一个是数据的保存位置,一个是相邻节点的指向。就是这俩造成了MongoDB和MySql的差别。
B+树相邻接点的指针可以大大增加区间访问性,可使用在范围查询等,而B-树每个节点 key 和data 在一起 适合随机读写 ,而区间查找效率很差。
- B+树相邻接点的指针可以大大增加区间访问性,可使用在范围查询等,而B-树每个节点 key 和data 在一起 适合随机读写 ,而区间查找效率很差。
- B+树更适合外部存储,也就是磁盘存储,使用B-结构的话,每次磁盘预读中的很多数据是用不上的数据。因此,它没能利用好磁盘预读的提供的数据。由于节点内无 data 域,每个节点能索引的范围更大更精确
逻辑结构和数据模型
MongoDB 与 MySQL 中的架构相差不多,底层都使用了可插拔的存储引擎以满足用户的不同需要。用户可以根据程序的数据特征选择不同的存储引擎,在最新版本的 MongoDB 中使用了 WiredTiger 作为默认的存储引擎,WiredTiger 提供了不同粒度的并发控制和压缩机制,能够为不同种类的应用提供了最好的性能和存储率。在存储引擎上层的就是 MongoDB 的数据模型和查询语言了,由于 MongoDB 对数据的存储与 RDBMS有较大的差异,所以它创建了一套不同的数据模型和查询语言。
数据模型
内嵌
内嵌的方式指的是把相关联的数据保存在同一个文档结构之中。MongoDB的文档结构允许一个字段或者一个数组内的值作为一个嵌套的文档
引用
引用方式通过存储数据引用信息来实现两个不同文档之间的关联,应用程序可以通过解析这些数据引用来访问相关数据。
存储引擎
存储引擎是MongoDB的核心组件,负责管理数据如何存储在硬盘和内存上。MongoDB支持的存储引擎有 MMAPv1 ,WiredTiger和InMemory。InMemory存储引擎用于将数据只存储在内存中,只将少量的元数据 (meta-data)和诊断日志(Diagnostic)存储到硬盘文件中,由于不需要Disk的IO操作,就能获取所需 的数据,InMemory存储引擎大幅度降低了数据查询的延迟(Latency)。从mongodb3.2开始默认的存储 引擎是WiredTiger,3.2版本之前的默认存储引擎是MMAPv1,mongodb4.x版本不再支持MMAPv1存储引擎。
配置
storage:
journal:
enabled: true
dbPath: /data/mongo/
##是否一个库一个文件夹
directoryPerDB: true
##数据引擎
engine: wiredTiger
##WT引擎配置
WiredTiger:
engineConfig:
##WT最大使用cache(根据服务器实际情况调节)
cacheSizeGB: 2
##是否将索引也按数据库名单独存储
directoryForIndexes: true
journalCompressor:none ##(默认snappy)
##表压缩配置
collectionConfig:
blockCompressor: zlib #(默认snappy,还可选none、zlib)
##索引配置
indexConfig:
prefixCompression: true
优势
-
文档空间分配
wiredTiger使用BTree NMAPV1线性存储, 需要padding
-
并发级别
wiredTiger 文档级别 MMAPV1 表级锁
-
数据压缩
snappy和zlib, MMAPV1无压缩
-
内存使用
wiredTiger可以指定内存的使用大小
-
cache
wiredTiger可以使用二级缓存WireTiger Cache, FileSystem Cache保证Disk上的数据最终一致性。wiredTiger只有journal日志。
文件
WiredTiger.basecfg: 存储基本配置信息,与 ConfigServer有关系
WiredTiger.lock: 定义锁操作
table*.wt: 存储各张表的数据
WiredTiger.wt: 存储table* 的元数据
WiredTiger.turtle: 存储WiredTiger.wt的元数据
journal: 存储WAL(Write Ahead Log)
原理
wiredTiger写操作会默认写入cache,并持久化到WAL中, 每60s或Log文件达到2G做一次checkpoint,初始化时,恢复到最新的快照状态,然后根据WAL恢复数据,保证数据的完整性.
Cache是基于BTree的,节点是一个page,root page是根节点,internal page是中间索引节点,leafpage真正存储数据,数据以page为单位读写。WiredTiger采用Copy on write的方式管理写操作(insert、update、delete),写操作会先缓存在cache里,持久化时,写操作不会在原来的leaf page上进行,而是写入新分配的page,每次checkpoint都会产生一个新的root page。
checkpoint
-
对所有的table进行一次checkpoint,每个table的checkpoint的元数据更新至WiredTiger.wt
-
对WiredTiger.wt进行checkpoint,将该table checkpoint的元数据更新至临时文件 WiredTiger.turtle.set
-
将WiredTiger.turtle.set重命名为WiredTiger.turtle。
-
上述过程如果中间失败,WiredTiger在下次连接初始化时,首先将数据恢复至最新的快照状态,然后根据WAL恢复数据,以保证存储可靠性。
Journaling
在数据库宕机时 , 为保证 MongoDB 中数据的持久性,MongoDB 使用了 Write Ahead Logging 向磁盘上的 journal 文件预先进行写入。除了 journal 日志,MongoDB 还使用检查点(checkpoint)来保证数据的一致性,当数据库发生宕机时,我们就需要 checkpoint 和 journal 文件协作完成数据的恢复工作。
-
在数据文件中查找上一个检查点的标识符
-
在 journal 文件中查找标识符对应的记录
-
重做对应记录之后的全部操作