利用JAVA向Mysql插入一亿数量级数据

利用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手工布局的原因、方法、工具和差异