字节二面:有一亿条数据,从Excel导入到MySQL中要如何处理?
这是最近面试官非常喜欢问的高频问题。有的同学会说,面试官又开始造火箭了,Excel里面能存一亿数据吗?
其实还真可以,虽然我们常用的xlsx格式最多只能存储100多万数据,但用csv格式进行数据存储,理论上还真是没有行数上限的。
接下来我们就分别从可行性、数据完整性和性能三个方面进行分析。
先说说可行性,如果我们使用常规Excel解析工具(如:Apache POI)进行处理,一次性地将Excel中的一亿条数据全部读取到内存中,并随后写入到数据库里,这是不可能实现的,JVM肯定会报OOM的。
因此,我们需要使用EasyExcel**之类的、支持流式处理方式的Excel解析工具。
它在处理海量数据从Excel中读取时,不会一次性将所有数据加载到内存中,而是采用边逐行读取边逐行处理,并即时释放内存的方式,大大减少了JVM的内存消耗。
我们可以看下EasyExcel处理海量数据的代码demo。
接下来聊聊数据完整性问题,如果给我们一亿条数据进行导入,我们肯定希望这些数据都能完完整整地导入到MySQL中。
如果在此过程中有零星数据导入失败的情况,我们也希望系统能够给我们返回是哪些数据导入失败了,以及具体失败的原因是什么,也就是具备可追溯性。
这样我们可以分析数据导入失败原因,将数据进行二次校准后再重新进行导入,继而实现数据完整性。
在性能方面,我们首先考虑的性能提升点,就是通过将单次落库改为批量落库。
因为BatchInsert操作无论是网络传输、SQL 解析、生成 SQL 执行计划,以及数据库的磁盘 IO这些方面,都从多次变成了一次,唯独业务数据量是相同的而已,这样性能一定是提升的。
我们可以通过引入线程池的方式实现批量落库的异步并行操作,将服务器硬件资源压榨到极致,并尽可能的来提升性能
另外一个性能提升点就是,我们可以在数据落库之前的校验阶段,通过completablefuture实现数据的并行校验来代替串行模式。
可行性、数据完整性和性能三个方面分析过后,我们再来聊聊数据库事务方面。
有的兄弟会有这样一个观点上的误区,他们认为在实现数据批量导入的时候要引入事务,但我们仔细想想事务具备哪些特性,ACID对吧,这里面的A代表原子性。
原子性的概念是,一系列数据库操作要么全部执行成功,要么全部不执行,不可处于部分成功部分失败的情况。
换句话说,如果一个批次往数据库中写入5000条数据,因为一条数据出现问题而使另外的4999条数据全部回滚,这是我们希望看到的结果吗?
当然不是,在这个场景我们要尽可能多地把正确的数据导入到数据库中,这才是我们的目标。
下次面试官再问起这个场景面试题,大家就按照我的方式进行回答,大家听明白了吗?