利用java向mysql插入一亿数量级数据—效率测评
这几天研究mysql优化中查询效率时,发现测试的数据太少(10万级别),利用 explain 比较不同的 sql 语句,不能够得到比较有效的测评数据,大多模棱两可,不敢通过这些数据下定论。
所以通过随机生成人的姓名、年龄、性别、电话、email、地址 ,向mysql数据库大量插入数据,便于用大量的数据测试 sql 语句优化效率。、在生成过程中发现使用不同的方法,效率天差万别。
1、先上mysql数据库,随机生成的人员数据图。分别是id、姓名、性别、年龄、email、电话、住址。
下图一共三千三百万数据:
在数据量在亿级别时,别点下面按钮,会导致navicat持续加载这亿级别的数据,导致电脑死机。~觉着自己电脑配置不错的可以去试试,可能会有惊喜
2、本次测评一共通过三种策略,五种情况,进行大批量数据插入测试
策略分别是:
mybatis 轻量级框架插入(无事务)
采用jdbc直接处理(开启事务、无事务)
采用jdbc批处理(开启事务、无事务)
测试结果:
mybatis轻量级插入 -> jdbc直接处理 -> jdbc 批处理。
jdbc 批处理,效率最高
第一种策略测试:
2.1 mybatis 轻量级框架插入(无事务)
mybatis是一个轻量级框架,它比hibernate轻便、效率高。
但是处理大批量的数据插入操作时,需要过程中实现一个orm的转换,本次测试存在实例,以及未开启事务,导致mybatis效率很一般。
这里实验内容是:
利用spring框架生成mapper实例、创建人物实例对象
循环更改该实例对象属性、并插入。
//代码内无事务 private long begin = 33112001;//起始id private long end = begin+100000;//每次循环插入的数据量 private string url = jdbc//localhost:3306/bigdata?useserverprepstmts=false&rewritebatchedstatements=true&useunicode=true&characterencoding=utf-8; private string user = root; private string password = 0203; @org.junit.test public void insertbigdata2() { //加载spring,以及得到personmapper实例对象。这里创建的时间并不对最后结果产生很大的影响 applicationcontext context = new classpathxmlapplicationcontext(applicationcontext.xml); personmapper pmapper = (personmapper) context.getbean(personmapper); //创建一个人实例 person person = new person(); //计开始时间 long btime = system.currenttimemillis(); //开始循环,循环次数500w次。 for(int i=0;i<5000000;i++) { //为person赋值 person.setid(i); person.setname(randomvalue.getchinesename()); person.setsex(randomvalue.name_sex); person.setage(randomvalue.getnum(1, 100)); person.setemail(randomvalue.getemail(4,15)); person.settel(randomvalue.gettel()); person.setaddress(randomvalue.getroad()); //执行插入语句 pmapper.insert(person); begin++; } //计结束时间 long etime = system.currenttimemillis(); system.out.println(插入500w条数据耗时:+(etime-btime)); }
本想测试插入五百万条数据,但是实际运行过程中太慢,中途不得不终止程序。最后得到52w数据,大约耗时两首歌的时间(7~9分钟)。随后,利用mybatis向mysql插入10000数据。
结果如下:
利用mybatis插入 一万 条数据耗时:28613,即28.6秒
第二种策略测试:
2.2 采用jdbc直接处理(开启事务、关闭事务)
采用jdbc直接处理的策略,这里的实验内容分为开启事务、未开启事务是两种,过程均如下:
利用preparedstatment预编译
循环,插入对应数据,并存入
事务对于插入数据有多大的影响呢? 看下面的实验结果:
//该代码为开启事务 private long begin = 33112001;//起始id private long end = begin+100000;//每次循环插入的数据量 private string url = jdbc//localhost:3306/bigdata?useserverprepstmts=false&rewritebatchedstatements=true&useunicode=true&characterencoding=utf-8; private string user = root; private string password = 0203; @org.junit.test public void insertbigdata3() { //定义连接、statement对象 connection conn = null; preparedstatement pstm = null; try { //加载jdbc驱动 class.forname(com.mysql.jdbc.driver); //连接mysql conn = drivermanager.getconnection(url, user, password); //将自动提交关闭 conn.setautocommit(false); //编写sql string sql = insert into person values (?,?,?,?,?,?,?); //预编译sql pstm = conn.preparestatement(sql); //开始总计时 long btime1 = system.currenttimemillis(); //循环10次,每次一万数据,一共10万 for(int i=0;i<10;i++) { //开启分段计时,计1w数据耗时 long btime = system.currenttimemillis(); //开始循环 while (begin < end) { //赋值 pstm.setlong(1, begin); pstm.setstring(2, randomvalue.getchinesename()); pstm.setstring(3, randomvalue.name_sex); pstm.setint(4, randomvalue.getnum(1, 100)); pstm.setstring(5, randomvalue.getemail(4, 15)); pstm.setstring(6, randomvalue.gettel()); pstm.setstring(7, randomvalue.getroad()); //执行sql pstm.execute(); begin++; } //提交事务 conn.commit(); //边界值自增10w end += 10000; //关闭分段计时 long etime = system.currenttimemillis(); //输出 system.out.println(成功插入1w条数据耗时:+(etime-btime)); } //关闭总计时 long etime1 = system.currenttimemillis(); //输出 system.out.println(插入10w数据共耗时:+(etime1-btime1)); } catch (sqlexception e) { e.printstacktrace(); } catch (classnotfoundexception e1) { e1.printstacktrace(); } }
1、我们首先利用上述代码测试无事务状态下,插入10w条数据需要耗时多少。
如图:
成功插入1w条数据耗时:21603成功插入1w条数据耗时:20537成功插入1w条数据耗时:20470成功插入1w条数据耗时:21160成功插入1w条数据耗时:23270成功插入1w条数据耗时:21230成功插入1w条数据耗时:20372成功插入1w条数据耗时:22608成功插入1w条数据耗时:20361成功插入1w条数据耗时:20494插入10w数据共耗时:212106
实验结论如下:
在未开启事务的情况下,平均每 21.2 秒插入 一万 数据。
接着我们测试开启事务后,插入十万条数据耗时,如图:
成功插入1w条数据耗时:4938成功插入1w条数据耗时:3518成功插入1w条数据耗时:3713成功插入1w条数据耗时:3883成功插入1w条数据耗时:3872成功插入1w条数据耗时:3873成功插入1w条数据耗时:3863成功插入1w条数据耗时:3819成功插入1w条数据耗时:3933成功插入1w条数据耗时:3811插入10w数据共耗时:39255
实验结论如下:
开启事务后,平均每 3.9 秒插入 一万 数据
第三种策略测试:
2.3 采用jdbc批处理(开启事务、无事务)
采用jdbc批处理时需要注意一下几点:
1、在url连接时需要开启批处理、以及预编译
string url = “jdbc//localhost:3306/user?rewritebatched-statements=true&useserverprepstmts=false”;
2、preparedstatement预处理sql语句必须放在循环体外
代码如下:
private long begin = 33112001;//起始idprivate long end = begin+100000;//每次循环插入的数据量private string url = jdbc//localhost:3306/bigdata?useserverprepstmts=false&rewritebatchedstatements=true&useunicode=true&characterencoding=utf-8;private string user = root;private string password = 0203;@org.junit.testpublic void insertbigdata() { //定义连接、statement对象 connection conn = null; preparedstatement pstm = null; try { //加载jdbc驱动 class.forname(com.mysql.jdbc.driver); //连接mysql conn = drivermanager.getconnection(url, user, password); //将自动提交关闭 // conn.setautocommit(false); //编写sql string sql = insert into person values (?,?,?,?,?,?,?); //预编译sql pstm = conn.preparestatement(sql); //开始总计时 long btime1 = system.currenttimemillis(); //循环10次,每次十万数据,一共1000万 for(int i=0;i<10;i++) { //开启分段计时,计1w数据耗时 long btime = system.currenttimemillis(); //开始循环 while (begin < end) { //赋值 pstm.setlong(1, begin); pstm.setstring(2, randomvalue.getchinesename()); pstm.setstring(3, randomvalue.name_sex); pstm.setint(4, randomvalue.getnum(1, 100)); pstm.setstring(5, randomvalue.getemail(4, 15)); pstm.setstring(6, randomvalue.gettel()); pstm.setstring(7, randomvalue.getroad()); //添加到同一个批处理中 pstm.addbatch(); begin++; } //执行批处理 pstm.executebatch(); //提交事务 // conn.commit(); //边界值自增10w end += 100000; //关闭分段计时 long etime = system.currenttimemillis(); //输出 system.out.println(成功插入10w条数据耗时:+(etime-btime)); } //关闭总计时 long etime1 = system.currenttimemillis(); //输出 system.out.println(插入100w数据共耗时:+(etime1-btime1)); } catch (sqlexception e) { e.printstacktrace(); } catch (classnotfoundexception e1) { e1.printstacktrace(); }}
首先开始测试
无事务,每次循环插入10w条数据,循环10次,一共100w条数据。
结果如下图:
成功插入10w条数据耗时:3832成功插入10w条数据耗时:1770成功插入10w条数据耗时:2628成功插入10w条数据耗时:2140成功插入10w条数据耗时:2148成功插入10w条数据耗时:1757成功插入10w条数据耗时:1767成功插入10w条数据耗时:1832成功插入10w条数据耗时:1830成功插入10w条数据耗时:2031插入100w数据共耗时:21737
实验结果:
使用jdbc批处理,未开启事务下,平均每 2.1 秒插入 十万 条数据
接着测试
开启事务,每次循环插入10w条数据,循环10次,一共100w条数据。
结果如下图:
成功插入10w条数据耗时:3482成功插入10w条数据耗时:1776成功插入10w条数据耗时:1979成功插入10w条数据耗时:1730成功插入10w条数据耗时:1643成功插入10w条数据耗时:1665成功插入10w条数据耗时:1622成功插入10w条数据耗时:1624成功插入10w条数据耗时:1779成功插入10w条数据耗时:1698插入100w数据共耗时:19003
实验结果:
使用jdbc批处理,开启事务,平均每 1.9 秒插入 十万 条数据
3 总结
能够看到,在开启事务下 jdbc直接处理 和 jdbc批处理 均耗时更短。
mybatis 轻量级框架插入 , mybatis在我这次实验被黑的可惨了,哈哈。实际开启事务以后,差距不会这么大(差距10倍)。大家有兴趣的可以接着去测试
jdbc直接处理,在本次实验,开启事务和关闭事务,耗时差距5倍左右,并且这个倍数会随着数据量的增大而增大。因为在未开启事务时,更新10000条数据,就得访问数据库10000次。导致每次操作都需要操作一次数据库。
jdbc批处理,在本次实验,开启事务与关闭事务,耗时差距很微小(后面会增加测试,加大这个数值的差距)。但是能够看到开启事务以后,速度还是有提升。
结论:设计到大量单条数据的插入,使用jdbc批处理和事务混合速度最快
实测使用批处理+事务混合插入1亿条数据耗时:174756毫秒
4 补充
jdbc批处理事务,开启和关闭事务,测评插入20次,一次50w数据,一共一千万数据耗时:
1、开启事务(数据太长不全贴了)
插入1000w数据共耗时:197654
2、关闭事务(数据太长不全贴了)
插入1000w数据共耗时:200540
还是没很大的差距~
借用:
分别是:
不用批处理,不用事务;
只用批处理,不用事务;
只用事务,不用批处理;
既用事务,也用批处理;(很明显,这个最快,所以建议在处理大批量的数据时,同时使用批处理和事务)
环旭电子与Asteelflash拟约4.5亿美元并购FAFG100%股权
中国通信业全面深化改革、通信央企做强做优做大的历史新篇
纸机导辊辊面腐蚀点蚀出现坑洞该如何处理
安世半导体与你约在元宇宙
SharpDevelop代码解析:AddInTree如何进行初始化工作
利用JAVA向Mysql插入一亿数量级数据
OnePlus 8T配备6.55英寸的‘Fluid AMOLED’显示屏
一种复制肺泡结构和功能的人类肺部芯片
BGA芯片底部填充胶点胶工艺标准和选择与评估
你知道如何去兑换央行的数字货币吗
人工智能元老发声:IBM在说谎,Watson就是一个骗局
光纤收发器测试流程和连接方式
干荷电铅酸蓄电池
FPC柔性电路板的生产流程
土壤温度、水分、盐分速测仪的作用是什么
超低功耗/超省电LCD液晶段码驱动IC-VKL076 SSOP28 FAE技术支持
半导体光电及激光智能制造技术会议
设计专利索赔!三星吐槽苹果要价太高
土壤养分检测仪厂家有哪些
FPGA手工布局的原因、方法、工具和差异