前言
最近使用mongo遇到了些问题,这里做个分享以及备忘!欢迎大家共同探讨学习!
1、mongo 排序报错(Sort operation used more than the maximum 33554432 bytes of RAM)
1.1、原因
- 由于MongoDB的sort操作是把符合条件的数据拿到内存中再进行排序的,默认给sort操作分配的内存为32MB,当符合条件的数据量超过32MB时,将会报错
1.1、解决办法 (从报错信息中我们可以得到解决办法)
- 给排序字段添加索引
(根据你排序的字段和顺序,合理创建索引可以解决)
db.myCollection.createIndex({ myOrderField1: 1, myOrderField2: -1 }, { background: true })
- 修改mongo配置,
加大内存如下加大到 320MB(举例哈,需要根据你的实际情况来决定加到多少)
db.adminCommand({setParameter:1,internalQueryExecMaxBlockingSortBytes:335544320};
2、mongo 分页问题 skip大(深分页情况下) 会有慢sql
伪sql : select * from tableOne where name=哈哈 skip a limit b
2.1、问题原因
- 这个问题和mysql差不多,都是需要逐行扫描直到第a条记录,如果a很大的时候(深分页情况下a将会很大)这类的分页sql将会很慢
2.2、解决办法 (1) 记录lastId
- 可以在每次分页返回后,记录最后一条数据的id我们暂且叫它
lastId,然后请求时带这这个lastId去 where id>lastId skip xxx limit yyy; 即可;但是当跳页时候,这个问题还是得不到根本解决(除非产品设计不能跳页只有下一页),另外如果你想使用类似mysql那种延迟关联来解决?对不起,不生效,任然很慢!
2.3、解决办法(2) 学学google
- google是使用了分页组思想,具体自行google,但是也解决不了跳页的问题
2.4、解决办法(2) 产品层面优化
- 从产品角度优化一下,比如限制时间范围(但这也是缓解问题,并不能真正解决问题)
2.5、解决办法(3) 换更高级的数据库
- 这个就没什么好说的了,我相信更换数据库的并不多,因为有成本呀!
3、mongo 分片后 使用upsert必须根据分片键当做where条件 否则将会报错
- 报错 :
An upsert on a sharded collection must contain the shard key
3.1、 问题原因
- 由于更新操作是下发到所有分片,如果更新条件不是分片键,可能会存在更新多条问题(因为除了分片键,其他字段均不唯一(这是mongo的龟腚))
3.2、解决办法
-
升级mongo数据库版本
-
不使用upsert
-
每次更新前查询出分片键,然后用分片键当做更新条件
4、mongo 分片时,不能有除分片键之外的唯一索引
- 这个没什么好说的,他是mongo的`龟腚
5、mongo 分片时,若表已存在且有数据,那么需要先建索引,在执行分片
5.1、原因
- 分片键
必须有索引
5.2、解决办法
- 分片前手动对分片键创建索引,
如果表不存在,你不创建的话他会自动给你创建,(当是空存在且有数据时候,最好是自己先建索引再分片!)
6、mongo 在in 条件中最好不要过多(同样的,sql也不宜过大过长),当sql过大过长时候,容易导致mongo服务器的cpu飙升
6.1、原因
- 这个是因为解析长sql需要耗费cpu,所以最好是避免这类长sql
6.2、解决办法
- 采用分批思想,查询时候一批一批查,写时一批批写即可(
分批思想在编程中很常见哦!)
7、慢sql
- 这个基本大家都知道了,就是加索引,但是在哪个字段加,加什么类型的索引,加索引后的效果,需要实际情况实际分析,另外还需集合
explain分析加索引后的效果如何,以达到最大优化
8、分片
- 这个是常用的一个优化手段,当表中数据量大时候,分片是很好的一个办法,并且是
水平分片,效果很明显。但是如何选择分片键是很关键的,你可以根据业务字段组合当分片键,也可根据_id来做分片键,另外还需要考虑分片键的索引类型,总之需要具体问题具体分析了。
结语
- 我想mongo的一些常见问题绝对不止这些,欢迎朋友们补充!