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