MongoDB批量处理
目录
排查线上生产环境问题,发现集合followInfo库里头部分集合(user_info_*)uid没有添加索引。由于查询是根据uid查询,为处理性能方面考虑,需要对followInfo 集合中的集合添加uid索引(不是唯一性索引)。
实际情况如下:
- followInfo 是一个库,库里有user_info_*集合(256个)以及其他不同名字的集合
- user_info_* 集合有的已经添加uid索引,有的没有添加。
- 部分user_info_*集合因为暂时没有数据,故该集合没有被创建,256中个集合大概有十个左右这样子的集合没有被创建。
- 存在的集合大概多二百一十多个,且每个集合数据量非常少,大概是一万多条数据。(也就说需要给大约二百多万条件数据添加索引)
目的:为user_info_*集合添加uid索引,并且检测那个集合没有添加成功的逻辑。
- 获取数据库
use followInfo; |
- 获取集合列表(使用变量进行保存)
var t=db.getCollectionNames(); |
- 遍历集合列表
t.forEach(function(item){ // TODO } |
- 判断集合是否存在
if(item.indexOf("user_info_") == 0) { // 假如存在则为0 // TODO } |
- 添加索引(添加索引一定要考虑实际情况添加!)
// 常规方式,当数据量大,或者线上有性能要求,且访问量大的情况下不可以用这种// 方式 db.getCollection(item).createIndex({ uid: NumberInt("1")}, { name: "uid",unique: false});
// background方式 db.getCollection(item).createIndex({ uid: NumberInt("1")}, { name: "uid", unique: false,background: true}); |
当给大量数据添加索引是,有可能会导致数据库阻塞。
原因如下:
MongoDB 锁是库级锁,建索引就是一个容易引起长时间写锁的问题,MongoDB 在前台建索引时需要占用一个写锁(而且不会临时放弃),如果集合的数据量很大,建索引通常要花比较长时间,特别容易引起问题。
解决的方法很简单,MongoDB 提供了两种建索引的访问,
一种是 background 方式,不需要长时间占用写锁。
另一种是非 background 方式,需要长时间占用锁。使用 background 方式就可以解决问题。 例如,为超大表 posts 建立索引, 千万不用使用。
db.posts.ensureIndex({uid : 1}) |
而应该使用
db.posts.ensureIndex({uid: 1}, {background: 1}) |
use followInfo; var t=db.getCollectionNames() t.forEach(function(item){ print(item.indexOf("user_info_")) if(item.indexOf("user_info_") == 0) { db.getCollection(item).createIndex({ uid: NumberInt("1")}, { name: "uid",unique: false}); } } ) print("end !") |
- 根据条件添加脚本(排除不存在的集合并初始化.)
use followInfo; for(var i= 0 ;i<256;i++) { var str = 'user_info_'+ i; var temp = db.str.exists(); if (temp == null) { db.getCollection(str).createIndex({ uid: NumberInt("1")}, { name: "uid",unique: false ,background: true });
} } print("end !") |
use followInfo; var t=db.getCollectionNames() t.forEach(function(item){ var index = db.getCollection(item).getIndexes(); if(index.length >= 2){ var temp = index[1] if(temp.name != null && temp.name != 'uid') print(item + " create indexs false !") } else { print(item + " create indexs false !") } } ) print("end !") |
执行之后应是会有这样的提示信息:
othercollection create indexs false ! (ps : 没有uid索引的才会提示!) end ! |
代表对othercollection 穿建脚本失败,othercollection 并不是本次处理的集合。
- 效果
以上脚本通过在命令行(或者执行js )执行后可以修库总某个集合下的索引问题。
通过这样的思路,可以对库总结合做更多的操作,例如重建索引,删除索引等等操作。
查询指定集合命令:
db.collectionName.getIndexes() |
查看指定集合状态信息
db.collectionName.stats(); |
- 脚本1跟2可以合并成一个脚本来写,这里为了分析知识点,减少理解的而复杂度故意拆分出两个脚本,在实际的运用过程中根据实际情况编写。
- 检测索引脚本
该脚本只是检测库中所有集合的脚本,假如某个集合没有uid集合时,会打印出 collectionName create indexs false !
可以改进只判断指定类型的集合。
N/A
若发现问题或者有更好的建议,请告诉我,不胜感激涕零!O(∩_∩)O哈哈~