这段时间正在使用SpringBatch重构公司的批处理系统,重构的目的是因为现在的批处理系统在性能上已经不能满足要求了,而且优化空间也非常有限。
在使用SpringBatch重构了其中一个任务后,做了测试,整体性能提长了一大半,执行时间缩短为原来的45%,效果还是很明显的,可喜的是还有优化空间,本文用来完整记录本次优化思路及过程。
本次优化是在SpringBatch框架基础之上的扩展!
适用版本
SpringBatch 3.0.8
Spring4.3
任务现状
SpringBatch的处理模型是ItemReader查询数据,将查询的数据一条(item)一条的给到ItemProcessor做业务逻辑处理,当处理的N条(一个chunk)后,执行ItemWriter批量更新数据。
插一句,使用了SpringBatch比原框架速度快了近60%的一个原因是,原框架处理完一笔数据后就commit,而SpringBatch框架的面向chunk的写数据(commit)充分的利用了JDBC的批量更新API,性能比单条数据commit好很多。
从如下UML序列图可以清楚的看到,ItemProcessor一次拿到一条数据,做业务逻辑处理,但做业务逻辑处理时所需要的数据ItemReader并不能完全提供,特别是一对多关系的数据。ItemReader一般只查询主表数据,子表数据是在ItemProcessor中查询(被迫),在这个任务中,需要进行额外的6个SQL的查询才能得到业务逻辑所需全部数据。
通过日志输出,一个process的处理耗时60-80耗秒,而6条SQL查询耗时就占了80%,可以看到性能主要是消耗在数据库查询上。如将降底查询耗时成为优化的主要目标。
优化思路
如果将process中的查询放到ItemReader中呢?ItemReader是分页来查询数据的,如果在分页查询完主表数据后,再把该chunk中的process中需要的子表数据全部查询出来,这次查询次数会大大降底。如果分页大小是500,该chunk的process需要执行500*6=3000次查询,优化后该只需要查询6次。
现在要做的就是将process中的查询SQL放到ItemReader中执行即可。这也是本文的主题:组合写。但是很遺憾,SpringBatch和MyBatis都没有提供复合读的功能,需要我们自己实现了。复合写MyBatis官方提供了API,见我头条另一篇文章:复合写。
复合读
1.配置主表查询ItemReader
配置主表查询ID
配置多个子表查询ItemReader
配置parameterValues,用于给子表查询的额外传参
2.配置子表查询ItemReader
配置子表查询ID
配置子表与主表关联的字段名称(fKField,pField)
配置子表查询触发模式,一次还是跟随主表查询
XML示例
注:复合写关键JAVA类:MyBatisPagingMuiltItemReader、MyBatisSubItemReader如果有需要的可以私信我。