mongoDB实战读书笔记
2021-10-15 17:37:25 150 举报
AI智能生成
mongoDB in Action 要点整理
作者其他创作
大纲/内容
第一章 简介
特征
面向文档
BSON格式(二进制json)
支持Ad hoc查询的nosql
即席查询
就是类似sql语句这种的,声明式查询,与命令式区别
索引
B树
LSM树
3.2版本可用
支持为字段添加二级索引,每个集合允许64个索引
持久化
写日志文件(op log)
默认开启 100ms写一次
存储引擎
WireTiger
扩展
基于范围分片
只在分片节点内冗余数据
基于hash和tag分片
复制
集合内可复制
自动容灾
工具
mongodump /mongosniff /mongostat /mongotop 等等
应用场景
可变的schema
数据集大小超过内存,会开始访问磁盘,速度变慢,mmap
第二章 mongo命令行
CRUD
创建
insert()
mongo中的库、集合在第一次插入数据时才会创建,不用手动创建
查询
find()/count()
条件关键字 $AND $OR $LT $GT
pretty()格式化
更新
update()
$set指定更新内容,否则执行替换更新
$unset去掉指定字段
$push更新集合
删除
drop()
删除集合
remove()
删除文档
高级查询
explain()
参数:
explain(工作模式)
关键输出:
totalKyesExamined 用到的索引数
totalDocsExcamined 遍历文档数
executionTimeMills 执行时间
索引
createIndex()
参数:{ 索引字段:索引名}
getIndexes()
数据库命令
db.stats()
数据库信息
db.cols.stats()
集合信息
db.currentOp()
监控当前操作
db.serverStatus()
集群维度的统计信息
connections
"connections" : {
"current" : <num>,
"available" : <num>,
"totalCreated" : <num>,
"active" : <num>
}
"current" : <num>,
"available" : <num>,
"totalCreated" : <num>,
"active" : <num>
}
命令执行原理
db.runCommand()
执行内建命令的函数
$cmd
内建命令集合
命令帮助
db.help()
查看命令源码
输入命令 但是不加括号
eg: 输入db.cols.save查看save()源码
eg: 输入db.cols.save查看save()源码
第三章 ruby驱动
mongo驱动作用
生成对象ID
时间+机器id+进程+计数器(4+3+2+3=12bytes)
对象和BSON格式之间转换
和数据库建立TCP连接
第四章 为业务设计mongo数据库
设计schema的技巧
设置唯一“主键”
设置一个slug字段,让它做唯一索引,保存一个便于阅读理解的key
比如商品编号 "IPhoneUsbCharger-34212"
不用ObjectId,因为ObjecID是一串无意义的字符
表示关联关系
因为mongo不支持join连接,所以可以直接把被关联的对象的信息保存在数据文档中 (也可以按关联对象的id查询,直接保存只是减少查询次数&最好保存不经常变动的信息)
比如 每个子类别不仅保存一个父类别的id,还保存了父类别的名称等(用户查询需要返回的信息)
这种方式 违反了数据库的第二,三范式
存在传递依赖,父类别改名时,所有子类别文档也要更新
不是每个属性都依赖主键
设计mongo 库、表时的限制
数据库限制 索引和集合数不能超过26000(WiredTiger引擎不限制)
创建数据库后,mongo会在/data/db目录创建一系列文件,以库名为前缀
xx.ns文件表示数据库xx的命名空间,固定大小16MB
16MB能保存不超过26000个元数据
可以通过修改--nssize改变限制
存储集合和索引的文件大小不超过2GB
mongo以预分配的方式在磁盘创建文件
扩容过程 64mb->128mb ... -> 2gb
db.stats() 输出的 fileSize表示数据库文件占用字节
总索引大小最好能够被装入内存
db.stats() indexSize查看全部索引大小
集合
集合名不超过128字符
固定集合(达到固定大小时,最先输入的记录被覆盖)
固定空间占用的集合(16kb等)
固定文档数的集合
TTL集合
用createIndex-- expireAfterSeconds创建一个管理超时时间索引
索引字段比较字段的值和当前时间差,超过expireAS会删除文档(不是删除集合)
固定集合不支持TTL
文档
尽量使用短的字段名,因为字段名也被大量保存
字符串必须用utf8编码
单个文档大小限制为16MB
文档嵌套深度最大值100
第五章 mongo支持的查询方式
查询语言
比较
$lt,$gt
db.xx.find({'age':{'$gt':20}})
范围
$in $all $nin
布尔查询
$ne $not $or $nor...
db.xx.find({'$and':['xxxxxx']})
包含某个字段
$exists
数组
包含某些字段 $elemMatch
大小 $size
自定义
$where 结合js函数查询
正则
前缀 表达式 可以用索引,其他不行
特殊查询
$mod 整除计算结果匹配
$type 字段类型匹配
$text 在文本上执行搜索
查询结果过滤
控制返回字段,再传一个参数值为1包含,0不包含
只返回 id db.xx.find({'name':'xx'},{'id':1})
跳过 多少个记录
$skip
返回数量
$limit
排序
$sort
返回一定范围
$slice
{$slice:-5} 最后5个
第六章 mongo的聚合查询框架
定义
mongo中的聚合类似于SQL中的group by
聚合管道
每一步的处理输出是下一步的输入
常用操作
$project
指定输出字段
$match
条件过滤
$group
根据指定key分组
$unwind
"展开,放松" 扩展数组,把每个元素为一个文档
$sort
$out
输出到新集合
示例
db.products.aggregate([{$match : ... } , {$group : ...},{$sort : ...},{ $out : ....}])
聚合操作内支持的函数
$group函数,用来改变输出集合的内容
$sum , $avg , $addToSet ....
$group:{ _id:{user:'$user_id', list: {$push: '$name'}}
字符串函数
$concat $substr $toLower .....
算术函数
$add $mod ...
日期函数
逻辑函数
集合操作符
处理输出的数组
$setUnion 合并两个集合
$setIntersection 返回公共元素
$setDifference 返回不同元素
....
聚合的性能
性能相关的选项
explain
返回聚合操作的查询信息,索引,扫描范围等
allowDiskUse
当处理大集合时,允许访问磁盘
cursor
用返回结果的指针来代替返回整个结果,减小返回数据大小
优化手段
在管道操作中减小文档的数量 和 大小
只有$match 和 $sort才能使用索引
使用分片集群时,$match和$project会在单个分片执行,其他的操作符会在主要片执行
????
map-reduce
需要自己编写js函数,比聚合出现早,但不再作为主要查询手段
第七章 mongo中的更新操作
更新操作
方式
update全部替换
update + $set 更新指定字段
网络传输的内容少
格式
db.xx.update( {查询条件},{$操作符:{更新内容},{更新选项}} )
选项
multi:true
批量更新,默认只会更新一个文档,不保证批量操作的原子性,需要自己处理失败
upsert:true
文档不存在时,插入新记录,新记录会合并查询和更新指定的字段做为内容
操作符
$inc N
N也可以是负数
$set
设置字段值
$unset
删除字段
$rename
重命名字段key
$setOnInsert:默认值
和upsert同时使用,在添加时使用默认值
数组操作符
$push $each $sort 等等
删除
remove全部文档
db.xxx.remove()
remove某些文档
db.xxx.remove({查询条件})
原子性操作
findAndModify
原子操作:(借助锁机制)相当于CAS操作,先查询获得结果然后更新,返回被更新的文档
限制
一次只能更新一个文档
参数
new:true
是否返回更新后的文档,否则返回更新之前的
sort
因为只能更新一个,可以用sort选择要更新的文档
upsert
如题 用upsert的方式修改
fields
控制文档返回的字段
$isolated操作符
db.xx.update( {$isolated:true} , {$set:xxx} )
使用它,表示当前操作是独立的,持有锁并阻塞其他操作
限制
在分片集合上无法使用
如果操作中途失败,mongo不会回滚数据
锁机制
WiredTiger引擎
支持文档级别的锁(SQL中的行锁)
老版本
数据库级别的锁
第八章 索引
基本概念
用B树实现
每个索引至少需要8kb空间 ???
被索引的字段最大不超过1024kb
可以通过索引文档个数和大小估算B树的内存占用
节点空间利用率为60% ??
非聚集索引
聚集索引的索引顺序和数据在磁盘的物理顺序一致
innodb的主键
mongo中的索引不是聚集索引,索引顺序和数据顺序没有关系
设计索引
保证索引大小能保存在内存中,避免磁盘I/O
索引越多,数据变化时,需要执行更新索引的操作越多
使用复合索引时,注意选择的字段顺序
索引类型
唯一索引
createIndex({unique:true})
保证索引字段在文档中唯一,插入重复数据会提示异常
唯一索引最好在填充数据前创建,否则需要手动对字段去重
多键索引
当索引字段是数组类型时使用,数组中的值都会保存在索引里
哈希索引
createIndex({recipe_name:'hashed'})
一般值相似的几个索引会保存在相邻的位置,Aa Abc Abb ....
哈希索引会把索引的值经过hash计算后再保存,这样索引会在集群中均匀分布(适合分片集合类型)
限制
不支持范围查询,仅支持等值查询
不支持多建索引
浮点数会被当做整数计算,4.2 和 4.3的索引相同
TTL索引
db.eventlog.createIndex( { "lastModifiedDate": 1 }, { expireAfterSeconds: 3600 } )
适用于时间类型字段
过期时间是 字段值X + expireAfterSeconds 秒
对嵌套的文档字段无效
操作索引
常用命令
db.collection. getIndexes() / dropIndex() / createIndex()
整理碎片
db.values.reIndex()
随着数据的变化,索引更新后会产生碎片
索引构建
大型数据库创建索引耗时会很长
处理办法
在后台构建索引
createIndex({background:true})
离线构建索引
复制主节点,构建索引,替换
索引创建过程中会对数据库加锁
构建执行步骤
对索引值做排序
把排序值插入索引
查看构建进度
db.currentOp()
索引优化
profile分析器
配置命令
db.setProfilingLevel(0/1/2,timeout)
0 禁用 1 记录慢操作 2 记录全部读写操作
查询监控结果
db.system.profile.find()
结果保存在system.profile集合
explain函数
xx.find(xx).explain("executionStats")
参数指定输出内容
参数
allPlansExecution/executionStats/queryPlaner
输出关注
nReturned
查询匹配和返回的文档数量
totalKeyExamined
查询扫描的文档数量,越小越好
mongoDB内置的查询优化器
选择最优索引组合成查询计划
生成的查询计划会被缓存一段时间
原则
避免scanAndOrder,如果要排序,优先尝试使用索引排序
优先使用满足所有查询字段的索引
第九章 文本搜索
第十章 WireTiger简介
可插拔的存储引擎接口
存储引擎
mongo数据库和硬件的直接接口
影响读写磁盘数据的方式,数据存储时的数据结构
v3.0提供了引擎切换的功能,满足不同使用场景的需要
wiredTiger
特点
多核可伸缩 Scalable Multicore Programming
风险指针和无锁算法的应用
使用mvcc架构
使用B树,可以切换LSM树
LSM在写入表现好,读表现差
文档级别的并发控制
多个客户端可以同时修改集合的不同文档
使用wiredTiger
确保64位系统
配置
engineConfig
cacheSize
申请多少内存
journalCompressor
使用哪种日志压缩器,默认snappy
collectionConfig
blockCompressor
集合数据压缩方式 默认snappy,可选zlib 或 none
indexConfig
prefixCompression
是否压缩索引,默认true
对比MMAPv1引擎
磁盘占用明显减少
mmap每次数据增长会申请2G的磁盘空间
性能对比
使用mongobenchmark执行测试脚本
读写性能wiredTiger优于mmapv1
开启压缩的wt在插入上比未开启压缩的wt慢,在读取上快,磁盘占用小
如果磁盘空间充足使用不压缩的wt
对比RocksDB
RockDB使用LSM树引擎,适用于高并发写入场景
mongoDB可以使用RocksDBm引擎
第十一章 副本集
副本集的特点
节点分为 主 从 裁判(arbiterOnly) 三种,可以包含50个节点(v3.0)
裁判不复制数据
提高读性能
不能保证一致性读(只有最终一致)
不适用 写请求大于读请求的场景
不适用于大数据集存储,需要使用分片代替
自动容灾
冗余数据
历史数据还是要备份快照,两者结合使用
副本集的命令
rs.initiate()
初始化
rs.reconfig()
重新配置,注意 配置变化会导致重新选举主节点
rs.add("pc.local:7000")
添加节点
rs.slaveOk()
开启从节点的读取,默认情况,从节点无法查询
db.isMaster()、rs.status()
副本集的节点信息
db.getReplicationInfo()
当前节点的数据复制情况
rs.help()
副本集命令帮助
工作原理
oplog介绍
保存在副本集每个节点的local数据库中
local数据库还保存了索引,集群选举信息等等重要数据
是一个固定大小的集合
64位系统默认大小为1G或者磁盘可用空间的5%
启动命令 mongod -oplogSize 设置自定义大小
记录节点所有数据变化,每条记录保存了 时间戳 ,操作类型, 操作数据 等
用oplog实现数据复制
主节点写入
操作记录到oplog
不会同步写所有从节点,通过writeConcern控制
从节点同步
通过长轮询请求,复制主节点oplog
根据本地oplog日志的时间戳,在主节点oplog中找到新产生的数据(找不到同步点,说明相差太多,要重新同步)
写入数据,更新本地oplog
实现自动容灾
心跳信息
2秒 ping一次,用来实现 容灾和选举的判断
节点挂了
挂从节点
不处理
挂主节点
选举新主节点
降级
主节点发现副本集只有自己,则自动降级为从节点
拒绝了写请求,可以避免数据无法冗余,丢失高可用
可以处理网络分区的问题,避免因为分区导致出现多个主节点
但不能完全避免,不一定只有主节点自身在一个网络分区,比如5个节点分成2+3
回滚
从节点复制时发现自己本地有主节点不存在的操作,则把这些操作回滚
从节点之前是主节点,然后挂了,有数据没被复制
管理副本集
每次重新配置都会重新选主节点
重新配置过程
config= rs.config()
config.members[1].host
假设修改第二个节点的host
rs.reconfig(config)
配置参数
priority
被选为主节点的优先级,0表示永远不做主节点
buildIndex
是否构建索引,备份节点不需要提供查询,设置为false
slaveDelay
复制的延迟时间,但是首先要配置节点优先级为0,才能生效
状态枚举
STARTUP
RECOVERING
FATAL
DOWN()
ROLLBACK
PRIMARY
SECONDARY
ARBITER
读写请求配置
写关注点
默认为1
设置为0,存在风险,无法正常故障转移
getLastError命令配置关注点
w
每次写要复制到几个服务器
wtimeout
写请求复制到其他节点的超时时间
读偏好
primary
唯一保证一致性读的模式
只读主节点
primaryPreffered
主优先,不可用读从库
secondary
只读从库
secondaryPreffered
从库优先
nearest
读响应延迟最低的节点
标签节点
每个节点都可以被打上 若干tag
通过getLastErrorModes命令,配置每次写到哪些标签,写标签中的几个节点
getLastErrorModes:{multiCity:{beijing:2},multiRegion:{us:3}}
定义了multiCity/Region两个模式,选择bj和us标签的节点
第十二章 分片集群
简介
分片集群结构
config service
保存集群元数据,数据在集群上的分布信息
提供高可用的持久化存储
两阶段提交更新配置
shard (replica set)
每个分片都是一个副本集
mongos进程
从config server读取节点,把客户端请求路由到合适的分片
把配置数据写到config server,使用两阶段提交
以独立进程运行,负责和客户端驱动连接
数据分片方式
基于“块”分片,“块”包含一个集合中的一部分文档
一个集合的文档会分布在多个片上
维护分片集群
创建
1.创建副本集
mongod --shardsvr --replSet xxx
2.创建config server
mongod --configsvr xxxx
3.启动mongos进程
mongos --configdb configserver(ip:port) xxx
4.连接mongos进程,执行分片命令
sh.addShard(xxx)
sh.enableSharding("shard db name")
sh.shardCollection("collection name",{分片键1,2,3...})
mongodb会在分片键上创建索引
数据迁移
分割
当数据“块”chunk size超过64mb,会分割成两个”块“
迁移
当数据在分片之间分布不均匀时发生
查看状态
分片集群状态
sh.status()
集群变动日志
use config; db.changelog.find()
balancer工作机制
文档介绍
管理分片集群数据
分片键选择
不要产生热点
分片键要让数据分布均匀
对查询友好,避免全局查询
分片键最好是查询常用的字段
不要让分片数据块的粒度过粗
分片键没有代表性,会使相同键的数据过多,超过分片单位"块"最大64mb的限制
不要使用objectID做分片键
objectID是自增的,新数据会集中到最后一个分片
查询
分类
目标查询:查询包含分片键
全局查询:查询不包含分片键
需要在每个分片执行查询
通过explain命令查看是否为全局查询
索引
分片集合在每个分片上的索引字段是一样的
只能在分片键和_id字段创建 唯一索引
部署最佳实践
减少使用的机器
副本集成员保存数据,需要单独的机器
副本集的裁判,不需要保存数据,可以和其他程序共享机器
config server实例,可以和其他程序共享机器
优化方式
要保证config server每个实例实时在线
当数量少于3台,配置服务器集群会变为只读,即没有主服务器,则分片集群不支持更改集群元数据的操作,例如块拆分和迁移。 虽然不能拆分或迁移任何块,但应用程序可以将数据写入分片集群(最多挂2台,否则停止服务)。
当加载大量数据到分片集合时怎样节省时间
使用预分割和预迁移的方式手动处理
添加分片耗时长
mongo集群,预估的数据迁移速度为100~200MB每分钟
在分片服务器内存占用到80%-90%之前就应该尽快提前迁移
0 条评论
下一页