MongoDB学习笔记
本文最后更新于:2022年6月13日 下午
MongoDB学习笔记
1.安装
1.1.Mac安装
官网 下载可执行文件包。选择本地部署,选择社区版服务端,选择你需要的版本,点击下载即可。
从大版本号6开始Mac版有ARM指令集可选,实际使用速度提升很高,但是截至本文创建时间,还没有形成稳定发布版本。
下载得到的压缩包中只有一个bin
文件包,内含4个最基本的服务端可执行文件。将mongodb
文件夹放至合适的位置,给bin
目录加环境变量。
1 |
|
创建log
和data
目录,用于存放日志和数据库数据(叫啥都行,你知道就行)。
使用以下指令开启和关闭服务端,此时可以命令行输入mongo
进入数据库shell。
--fork
指令用于指定后台运行,而后台运行没有对应的指令一键退出,需要进入shell后输入db.adminCommand({ "shutdown" : 1 })
。如果你确定你的数据库目前没有读写,而且是单机运行,那么也可以直接杀掉进程。
1 |
|
1.2.数据迁移
MongoDB提供直接输入输出数据库到文件的功能,可以用于数据库迁移。进行这些操作需要补充可执行文件。官网下载即可。目前数据库工具还没有苹果ARM版本。
下载的压缩包中同样只有一个bin
文件夹,里面补充了一些可执行文件。将它们复制到你MongoDB的bin
目录中。
数据库导出也可以使用JetBrains全家桶的数据库插件,它可以一次性导出一整个库,效率比较高,但是不提供导入功能。mongodb官方也提供免费的GUI管理器——Compass。它提供完整的数据库操作、分析、导入导出功能。
1 |
|
1.3.多节点部署
在单机上模拟多节点配置。对于实际生产环境不建议单机配置。
1.3.1.配置文件
创建三个不同的数据文件夹,分别在其内创建配置文件mongod.conf
,写入如下配置内容。三个加了注释的地方要根据实际来改动,三个节点不准相同。
1 |
|
1.3.2.配置复制集
命令行中输入以下命令,启动三个mongodb进程:
1 |
|
三个进程目前互相独立,互不知道,因此需要进入shell进行进一步配置:
1 |
|
配置方式有如下两种,任一即可。
1 |
|
1 |
|
1 |
|
想要在从节点上读取数据(比如搜索)默认被禁止,如果想启用,请在从节点的命令行输入
rs.secondaryOk()
1.3.3.调整配置
1 |
|
2.shell操作
2.1.基本操作
show dbs
,显示所有数据库。use [数据库]
,使用某数据库db.collection.insertOne([Json])
插入一条数据;db.collection.insertMany([Json,Json,Json])
同时插入很多条数据。插入后会返回给你ObjectId
字段查找
db.movies.find().pretty()
,显示所有数据,且有缩进db.movies.find({"year":1975},{"_id":0,"title":1}).sort("age":1)
,单条件查询,且不返回id返回title,且排序db.movies.find({"year":1989,"title":"Batman'"})
,多条件and查询db.movies.find($and:[{"title":"Batman},{"category":"action"}])
,and的另一形式db.movies.find({$or:[{"year":1989},{"title":"Batman"}])
,多条件or查询db.movies.find({"title”:/^B/})
,按正则表达式查找逻辑对照
子文档中如果有多个属性,搜索时应当搜索「子文档属性是…」,而不是「子文档是 属性…」。二者表达意义不同。
如果某个属性是一个数组,搜索的元素在此数组中,那么就是可以搜到的。
对子文档搜索时,使用
$elemMatch
指定的字段必须在同一条数据里
删除
db.testcol.remove( { a : 1 } )
,删除a 等于1的记录db.testcol.remove( { a : { $lt : 5 } } )
,删除a 小于5的记录db.testcol.remove( { } )
,删除所有记录db.testcol.remove()
,报错
更新
db.fruit.updateOne({name: "apple"}, {$set: {from: "China"}})
,查询字段和更新字段都是必须的- 必须有如下操作符至少一个
$push
:增加一个对象到数组底部$pushAll
:增加多个对象到数组底部$pop
:从数组底部删除一个对象$pull
:如果匹配指定的值,从数组中删除相应的对象$pullAll
:如果匹配任意的值,从数据中删除相应的对象$addToSet
:如果不存在则增加一个值到数组
删除
db.[集合].drop()
,删除一个集合db.dropDatabase()
,删除一个数据库
索引
1 |
|
2.2.聚合查询
- 操作符
- 运算符
- 特有操作
- 例1
- 例2
- 特有操作
- 自动分组
- 一次完成多个分组
2.3.设计模式
- mongodb使用中,通常直接把数据放到一个表里,除非超过了16M
- 分表后可以这样聚合查询
- 只支持左外连接,不能是分片表
- 推荐的设计模式
- 表现形式类
- 列转行
db.movies.createIndex({"releases.country":1,"releases.date":1})
- 文档版本
- 列转行
- 数据访问类
- 子集
- 近似处理:每次写操作触发0-9随机数,随机数在0才计数加10。减少写操作
- 组织结构类
- 预聚合:数据中提前储存统计字段
- 分桶:把每分钟的数据改成每小时一个表,其中的数据用数组存
- 表现形式类
2.4.事务
写操作
writeConcern
:一个写操作落到多少个节点上才算成功。发起写操作的程序将阻塞到写操作到达指定的节点数为止db.test.insert( {count: 1}, {writeConcern: {w: "majority", wtimeout:3000 }})
- 0:不关心是否成功
- 1:写入全部节点
majority:大多数节点
journal
:写操作到达多少个节点才算成功- true:写操作落到journal文件中才算成功
- false:写操作到达内存即算作成功
配置延迟节点
1 |
|
读操作
readPref
:决定使用哪一个节点来满足正在发起的读请求- primary:只选择主节点
- primaryPreferred:优先选择主节点,如果不可用则选择从节点
- secondary:只选择从节点
- secondaryPreferred:优先选择从节点, 如果从节点不可用则选择主节点
- nearest:选择最近的节点
可以自己打标签,例如为3个较好的节点打上
{purpose:"online"}
readConcern
:决定这个节点上的数据哪些 是可读的,类似于关系数据库的隔离级别- available:读取所有可用的数据
- local:读取所有可用且属于当前分片的数据
- majority:读取在大多数节点上提交完成的数据
- linearizable:可线性化读取文档。性能一般,一般用不到
- snapshot:读取最近快照中的数据。最高安全级别
读写分离提高性能
db.orders.insert({ oid: 101, sku: "kiteboar", q: 1}, {writeConcern:{w: "majority"}})
db.orders.find({oid:101}).readPref("secondary").readConcern("majority")
2.5.变更流(触发器)
- 与触发器不完全相同
db.test.watch( [], {maxAwaitTimeMS:300000} )
,通过另一个命令行插入了数据,就会有提示
2.6.开发要点
- 如果一个游标已经遍历完,会自动关闭。如果没有遍历完,则需要手动调用
close()
方法,否则该游标将在服务器上存在 10 分钟(默认值)后超时释放,造成不必要的资源浪费 - 索引
- 没有资源隔离,一个没有索引的慢查询可能影响到所有其他操作。尽量使索引覆盖要查询的内容,避免查询数据文件
- 使用
projection
减少返回到客户端的的文档的内容
- 写入
- 在 update 语句里只包括需要更新的字段
- 尽可能使用批量插入来提升写入性能
- 文档结构
- 防止使用太长的字段名(浪费空间)
- 防止使用太深的数组嵌套(超过2层操作比较复杂)
- 不使用中文,标点符号等非拉丁字母作为字段名
- 分页
- 使用limit限制返回的条数,避免遍历整个数据库
db.coll.find({x: 100}).limit(50)
- 分页跳转代替传统遍历
- 使用limit限制返回的条数,避免遍历整个数据库
- 事务
- 尽可能不用
- 不要过大(1000个文档更新以内),因为有60s限制
- 当必须使用事务时,尽可能让涉及事务的文档分布在同一个分片上
- 实际操作参数
- 禁用 NUMA,否则在某些情况下会引起突发大量swap交换
- 禁用 Transparent Huge Page,否则会影响数据库效率
- tcp_keepalive_time 调整为120秒,避免一些网络问题
- ulimit -n,避免打开文件句柄不足的情况
- 关闭 atime,提高数据文件访问效率
3.python操作
3.1.基本操作
1 |
|
1 |
|
1 |
|
1 |
|
3.2.spark+mongo
- 架构图
- 具体操作:坑比较多,python对spark的数据格式支持还不是很好。以后再写
4.架构
4.1.复制集
原理:mongodb要求奇数个(通常是3)节点来保证投票机制,主节点负责读写,从节点无写入能力,只能读或者从主节点把数据同步过来。当一个修改操作到达主节点时,对数据的操作将被记录下来(经过一些必要的转换),这些记录称为oplog。从节点通过在主节点上打开一个tailable游标不断获取新进入主节点的oplog,并在自己的数据上回放,以此保持跟主节点的数据一致
实现:具有投票权的节点之间两两互相发送心跳,当5次心跳未收到时判断为节点失联。如果失联的是主节点,从节点会发起选举,选出新的主节点;如果失联的是从节点则不会产生新的选举。选举基于RAFT一致性算法实现,选举成功的必要条件是大多数投票节点存活。复制集中最多可以有50个节点,但具有投票权的节点最多7个
选举条件
- 大多数节点存活
- 新的主节点
- 能与多数节点建立连接
- oplog较新
- 优先级较高(如果有配置)
- 复制集节点常见选配项
- 是否具有投票权(V参数)
- 优先级(priority参数):越高越好,0不能成为主节点
- 隐藏(hidden参数):复制数据,但对应用不可见。可以具有投票仅,但优先级必须为0
- 延迟(slaveDelay参数):复制n秒之前的数据,保持与主节点的时间差
- 增加节点不会提高写操作性能
4.2.分片集
- 需要多种不同类型节点
- mongos路由节点,提供唯一访问入口。三台是做了高可用冗余,实际一台也行
- config配置节点,分片集元数据,包括集群分片的索引映射等。三台是做了高可用冗余
- 每个分片必须是一个复制集
- 应用透明、自动均衡、动态扩容、提供三种分片方式
- 基于范围:范围查询性能好,但数据分布可能不均匀
- 基于哈希:数据分布均匀,写优化,但范围查询效率低。适用于日志,物联网等高并发场景
- 基于Tag:自定义
- 额外消耗比较大,管理复杂
- 分片数的计算:取最大值
- 总数据量 / 硬盘(<2T)
- 热数据+索引 / 内存 * 0.6
- 总并发量 / 并发量 * 0.7
4.3.索引
- 索引的结构
- 建议优先使用过滤性强的字段作为索引
- 查询时后面加上
.explain(true)
可以打印详细的检索信息 - 精确匹配写在最前面,排序字段写中间,范围匹配放在最后来建索引
- 地理位置索引
- 部分索引
- 全文索引
4.4.性能监控
mongostat
,监控过去1秒内所有资源使用情况。脏数据超过20%或内存占用超过物理内存的60%的95%时阻塞新请求mongotop
,排查是哪个表的读写消耗性能pip install mtools
,使用python可视化展示性能情况mplotqueries [日志文件]
,将所有慢查询通过图表形式展现mloginfo --queries [日志文件]
,总结所有慢查询的模式和出现次数、消耗时间等
4.5.全球集群
- 架构图
- 可以做到多个主节点同时读写
- 模型中增加区域字段、分片中加区域标签、给每个区域指定分片块范围
参考链接
本博客所有文章除特别声明外均为原创,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!