当前位置:   article > 正文

mongodb大批量删除数据的方案对比_mongotemplate删除大量数据

mongotemplate删除大量数据

业务背景

系统中有个mongodb集合每天增长上千万,时间长了,系统中这个集合已经有几亿数据了,需要写一个定时任务,把集合中三个月前的数据删除,并且后面每天凌晨执行这个定时任务.

方案分析

方案一

使用Mongo的游标MongoCursor,遍历获取集合id获取id列表idList,然后根据idList批量删除

方案二

使用mongoTemplate.find,每次查询1万条数据,遍历获取集合id获取id列表idList,然后根据idList批量删除

代码片段

方案一

  1. /**
  2. * 删除集合数据
  3. *
  4. * @param time 传三个月前的时间戳
  5. */
  6. private void deleteData(Long time) {
  7. Query query = new Query(new Criteria("ct").lt(time));
  8. MongoCursor<Document> dbCursor = mongoTemplate.getCollection(COLLECTION_NAME)
  9. .find(query.getQueryObject())
  10. //设置游标查询不超时
  11. .noCursorTimeout(true)
  12. //设置批量从数据库中获取的数据量
  13. .batchSize(10000)
  14. .iterator();
  15. int i = 0;
  16. List<String> idList = new ArrayList<>();
  17. Document next;
  18. while (dbCursor.hasNext()) {
  19. i++;
  20. next = dbCursor.next();
  21. String id = next.get("_id").toString();
  22. idList.add(id);
  23. if (i % 10000 == 0) {
  24. List<String> idListToDelete = new ArrayList<>();
  25. idListToDelete.addAll(idList);
  26. // 清空数据
  27. idList.clear();
  28. log.info("delete: {}", i);
  29. // 异步删除数据
  30. threadPool.execute(new Runnable() {
  31. @Override
  32. public void run() {
  33. doDeleteData(idListToDelete);
  34. }
  35. });
  36. }
  37. }
  38. // 再次判断
  39. if (CollectionUtils.isNotEmpty(idList)) {
  40. doDeleteData(idList);
  41. idList.clear();
  42. }
  43. log.info("data delete total: {}", i);
  44. }

方案二

  1. /**
  2. * 删除集合数据
  3. *
  4. * @param time 传3个月前时间戳
  5. */
  6. private void deleteData(Long time) {
  7. Query query = new Query(new Criteria("ct").lt(time));
  8. // 只需要去_id字段即可,避免取多个字段,数据量大了占内存过多
  9. query.fields().include("_id");
  10. query.limit(10000);
  11. List<XXX> xxxList = mongoTemplate.find(query, XXX.class);
  12. List<String> idListToDelete;
  13. int i = 0;
  14. while (CollectionUtils.isNotEmpty(xxxList)) {
  15. i += xxxList.size();
  16. idListToDelete = xxxList.stream().map(o -> o.getId()).collect(Collectors.toList());
  17. doDeleteData(idListToDelete);
  18. log.info("delete: {}", i);
  19. xxxList = mongoTemplate.find(query, XXX.class);
  20. }
  21. log.info("delete total: {}", i);
  22. }
  1. /**
  2. * 执行删除数据
  3. */
  4. private void doDeleteData(List<String> idList) {
  5. long s0 = System.currentTimeMillis();
  6. Query query = new Query(new Criteria("_id").in(idList));
  7. mongoTemplate.remove(query, XXX.class);
  8. long s1 = System.currentTimeMillis();
  9. log.info("delete data size: {}, cost: {}", idList.size(), (s1 - s0));
  10. }

对比

两种方案都是可行的,只不过是速度上的差别,大致速度如下(当时没有记录数据,大致是这个速度)

发送量方案一(游标)方案二(query)
10万7s4s
400万7分2分

总结

实际在测试的过程中,发现删除数据其实花费时间很少,大概200多毫秒删1万条,但MongoCursor在遍历循环的时候比较耗时while (dbCursor.hasNext()) { }。

而mongoTemplate.find在查询的数据的时候,如果数据有索引,每次查询1万条其实速度是挺快的,根据找到符合条件的1万条数据,立即返回。(顺便说下,mongoTemplate.count计算总数比较慢)

遇到类似的问题,可以结合业务,对两种方案进行测试,一般第二种方案效率更高一点。

有其他更好的方案欢迎交流!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/酷酷是懒虫/article/detail/735507
推荐阅读
相关标签
  

闽ICP备14008679号