项目场景:
项目中涉及到接口人员同步,大约10万级数据量,但是在插入数据库的过程中发现很多问题,记录一下。
问题描述:
因为表中字较多,第一次插入数据库花了10多分钟,实在受不了,最终优化10万数据量插入数据库大约19秒左右。
解决方案:
解决方案一
第一次优化是在mysql链接的参数上面
批量插入:
&rewriteBatchedStatements=true
&allowMultiQueries=true
这两个参数非常重要,提升很明显,配置完从10多分钟优化到3分钟左右
解决方案二
执行分批插入,用的是MybatisPlus自带的saveBatch()方法
每批分500,循环插入,从3分钟优化到2分钟
解决方法三
多线程分批插入
测试类
@Test
public void testMulBatch() throws InterruptedException{
ExecutorService es = Executors.newFixedThreadPool(5);
CountDownLatch c = new CountDownLatch(100);
List<User> users = new ArrayList<>();
for(int i =0 ; i<1000000; i++){
User user = new User();
user.setId((long)i);
user.setAge(i);
user.setName("dawdawdawdaw"+i);
user.setEmail("dawdwadwa@adwda.com");
users.add(user);
}
long begin = System.currentTimeMillis();
for(int i= 0;i<100;i++) {
es.submit(new MyThread(users.subList(i*10000,(i+1)*10000),c,userService));
}
c.await();
es.shutdown();
long end = System.currentTimeMillis();
System.out.println("批量插入时间"+(end-begin));
}
线程类
class MyThread implements Runnable {
private CountDownLatch c;
private UserService userService;
private List<User> users;
public MyThread(List<User> users, CountDownLatch c, UserService userService) {
this.c = c;
this.users = users;
this.userService = userService;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
userService.saveBatch(users);
c.countDown();
}
}
优化结果还是挺明显的,大致从2分钟提升到30多秒
解决方法四
因为看到控制台打印的sql语句发现,插入参数个数不同,导致saveBatch()变成一条一条的插入。mybatisplus可以帮你补全参数,但是要配置一下
public class EasySqlInjector extends DefaultSqlInjector {
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
//防止父类方法不可用
List<AbstractMethod> methods= super.getMethodList(mapperClass);
methods.add(new InsertBatchSomeColumn());
return methods;
}
}
@Configuration
public class MybatisConfig {
@Bean
public EasySqlInjector easySqlInjector() {
return new EasySqlInjector();
}
}
public interface UserMapper extends BaseMapper<User> {
Integer insertBatchSomeColumn(List<User> entityList);
}
调用类
userService.getBaseMapper().insertBatchSomeColumn(users);
通过以上4次优化,现在最终插入时间为19秒。
总结
大批量数据插入数据库时首先把大化小,先考虑在代码上优化,多线程,分批等方案。在考虑表结构和sql语句,最终Mysql数据库本身参数问题。