MybatisPlus查询百万数据的内存占用问题?

我在表里添加了500W的测试数据,表中数据如下
image.png
一次性读取 500w 数据到 JVM 内存中 必然会造成OOM现象,所以我分别试验了2个读取百万数据的方式,并用Junit分析内存占用

  1. 分页多次查询,并进行深度分页优化
  @Test
    void testPage(){
        //查询出表中总记录数
        Long total = orderMapper.selectCount(null);
        //每次分页读取的结果数
        int fetchSize = 100000;
        // 分页优化参数,上次查询的最大ID
        int lastMaxId = 0;
        for (int i = 0; i < (total / fetchSize) + 1; i++) {
            LambdaQueryWrapper<Order> orderLambdaQueryWrapper = new LambdaQueryWrapper<>();
            orderLambdaQueryWrapper.gt(Order::getOrderId, lastMaxId);
            List<Order> records = orderMapper.selectPage(new Page<>(1, fetchSize), orderLambdaQueryWrapper).getRecords();
           records.stream().forEach(System.out::println);
            //获取本次最大的Id
            lastMaxId = records.get(records.size() - 1).getOrderId();
        }

    }

image.png

  1. Mybatis的流式查询
  @Test
    void testStream() {
        orderMapper.selectList(Wrappers.emptyWrapper(), resultContext -> {
            // 依次得到每条业务记录
            System.out.println("当前处理第" + resultContext.getResultCount() + "条记录.");
            Object order = resultContext.getResultObject();
            System.out.println(order);
            //做自己的业务处理,比如分发任务
        });
    }

image.png

我从网上看了许多博客,说流式查询可以很好避免OOM问题。
但是为什么在分析堆内存占用中,反而是 多次分页查询的内存占用更小,平均只有400MB
而流式查询却能高达平均1GB的占用?

关于如何开启流式查询是参考的MybatisPlus官网,MybatisPlus版本是也最新的。https://baomidou.com/pages/1922u2/
阅读 1.4k
avatarAI BotBETA

多次分页查询和流式查询都是处理大量数据的常用策略。它们的工作原理和内存占用情况有所不同。

  1. 多次分页查询:这种策略是按照分页的方式逐步获取数据,每次只读取一小部分数据到内存中,因此它对内存的占用相对较小。在你的测试中,每次读取的数据量约为10万条,所以内存占用约为400MB。
  2. 流式查询:这种策略是逐步读取数据,并对每条数据进行处理,而不是一次性将所有数据加载到内存中。因此,流式查询的内存占用通常比多次分页查询要小。然而,在你的测试中,流式查询的内存占用却比多次分页查询要高,这可能是因为流式查询在处理每条数据时都会创建一个新的对象,而这个对象的销毁时间比较长,导致内存占用较高。

另外,你提到你参考了MybatisPlus的官方文档开启流式查询,但是你没有提到具体的开启方式。流式查询是否开启成功以及是否正确使用,可能也会影响内存占用情况。建议你仔细检查你的代码以及流式查询的使用方式,确保你正确地使用了流式查询。

总的来说,对于处理大量数据,多次分页查询和流式查询都有各自的优点。你可以根据你的实际需求和系统资源情况来选择适合的策略。如果你的系统内存资源充足,并且你需要一次性处理大量数据,那么流式查询可能是一个更好的选择。如果你的系统内存资源有限,或者你只需要处理一部分数据,那么多次分页查询可能更适合你。

1 个回答

因为流式查询也不是一条一条的流,而是一次获取一批数据,处理完了再获取下一批
原理和分页类似但是效率比分页高,因为分页需要‘跳过’前面的记录,而流不需要
如果需要优化的话,找到 fetch size 之类的东西配小一点就行

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏