百万级数据导出优化方案
数据的导出功能相信大家在平时的工作当中已经非常熟悉了。导出本来就是一个很简单的功能,使用一些工具类,然后查询出所有数据直接调用工具类就可以道出了、既然这样为什么还要写这篇文章呢??
主要是最近在做的一个功能也是导出的,但是数据量达到了百万级别、。我们知道导出的流程一般是
查询出所有要导出的数据 --->调用工具类导出
这些查询出来的数据都是放在内存中的,这时候就会有问题了。如果你的数据量特别大,大到直接把你内存撑爆了怎么办? 这时候就会报 OOM 错误了、。下图就是我导出数据的时候内存使用图。这些数据还没有达到我线上的数据量。如果你的数据达到千万级别,那又该怎么办呢? 接下来我提供二种解决方案
方案一
无论怎么样我们都是要将所有的数据都找出来,然后导出的,既然一次性查询出来的数据量太大,我们是不是可以分批次的导出呢,比如一次就导出 10 万条数据,然后让前端多调几次导出的接口,这样就可以解决大数据内存占满的情况。
表面上这个问题是解决了。但是你有没有想过,前端怎么知道你有多少数据呢? 不知道数据多少又怎么知道需要调几次呢?
我既然说了可以分批次导出,那就肯定可以,既然前端不知道,那就让前端就调一次我们的接口,分批次的任务由后端解决。
相信大多数都是使用的是 MyBatis,接下来我要提出的就是 MyBatis 的一个非常强大的功能。,那就是 MyBatis 的流式查询
它可以分批次查询。,所有的业务逻辑都不变,就是在将之前的普通查询改成流式查询,在使用流式查询之后,内存的使用如下图。只有 100 多 MB,数据还是一次性的导出来了
方案二
第二种方案呢大家就比较难想到了。具体的步骤如下:
还是分批次的查询,但是这时候你还是使用普通的查询,不是使用流式查询,比如一次查询 10 万条
将数据导出的文件保存到服务器的一个目录,比如文件-1
查询下一个批次的数据,数据导出的文件保存到服务器的一个目录,比如文件-2,直到将所有的数据都导出来了
数据合并,Java 是可以调 shell 脚本的,你只需要写好一个 shell 脚本将这些文件进行合并即可
合并的文件重新命名,然后将地址返回给前端
前端获取到这个文件的地址之后,就可以直接进行下载了
作者:我是小趴菜
链接:https://juejin.cn/post/7236021828999970875
来源:稀土掘金
评论