我们数据库里有4000W数据,现在想将里面的数据规整一下放到另一张表里(数据类型规整),于是写 了java个程序进行类型转换,然后一条条的查出来处理后再插入到mongo里,在此之前也有过这样的经历,但是并不是一次性存入这样大量的数据,没有瓶颈存在,后来发现当我总数100W左右,整个程序就会假死状态,不能查询也不能插入,刚开始我认为是mongo性能瓶颈了,于是去查看服务器,发现cpu,内存,连接数都很正常,一点都不高,就是不执行;监听Java堆栈也未发现异常,很奇怪,也没找到原因;再后来分析因为我是insertOne,mongo在插入数据的时候会有一次数据验证,比如ObjectId是否重复等,也许是我这种连续插入让mongo这个验证卡住了,,暂时锁住了表。。当我退出程序,,锁就自动关了(个人)
mongo的查询,使用cursur查询的时候,如果没有设置batch size这个参数,那么mongo默认会返回101条数据,等这101条数据读取完了,也就是想读取第102条的时候,那么驱动会再去数据库读取下一批数据,这批数据不是用条数来限定的,而是最大限制为4m,放入内存,等该数据读完了再去取下一次4M; mongo本身为异步读写;
但我觉得并不是这样,因为我每一次查询的时候都driver都会有日志输出(mongo Java driver)自带的,每一次都会去请求数据库,我还是认为是我的链接太频繁让mongo连接池卡住了(读写)
于是我手动设置了batchSize后,发现读取的时候不会每一次都有日志输入了,说明它真的是每一次去拿50000条数据,一次链接申请;
再使用insertMany,却发现每次最大写入为1000条,这个速度已经赶上我开50个线程用最开始的单条读写了(现在为单线程);
public static void insert(Document query){
FindIterable<Document> findIterable = mv150.collection.find(query).batchSize(50000);//batchSize 设置每次取出数据量
MongoCursor<Document> cursor = findIterable.iterator();
InsertManyOptions options = new InsertManyOptions();//不开启验证/ 效率更快
options.ordered(false);
//ExecutorService executorService = Executors.newFixedThreadPool(100); 本来最开始想用多线程
final List<Document> list = new ArrayList<>();
while(cursor.hasNext()){
final Document d = cursor.next();
list.add(resetBDLPType(d));
if(list.size()==50000){
/* executorService.submit(new Runnable() {
@Override
public void run() {
mvbasic.collection.insertMany(list);
}
});*/
mvbasic.collection.insertMany(list,options);
list.clear();
}
}
cursor.close();
}
后来找到验证开关,并关闭了开关,效率是高了不少,具体效率高了多少没有测,反正count数据的时候比刚才没有关闭的时候快多了
InsertManyOptions options = new InsertManyOptions();//不开启验证/ 效率更快
options.ordered(false);
final List<Document> list = new ArrayList<>();
while(cursor.hasNext()){
final Document d = cursor.next();
list.add(resetBDLPType(d));
if(list.size()==50000){
mvbasic.collection.insertMany(list,options);
list.clear();
}
}