天天看点

数据库批量数据插入问题分析

  在数据库的相关开发中,经常会遇到数据的批量插入问题。本文主要是通过实验的方式探讨批量数据插入的瓶颈,以及优化建议。

以10w条记录的插入作为实验对象,采用下面的几种方法插入:

1.       普通插入:普通的一条条插入

2.       普通插入+手动提交:setAutoCommit(false)、commit()

3.       普通插入+手动提交+ prepareStatement方式

4.       批量插入:addBatch、executeBatch

5.       批量插入:insert into tableName (x,xx,xxx) values(x,xx,xxx),(xx,xxx,xxxx)…,

6.       多线程插入。

7.       InnoDB引擎和MyISAM引擎的比较。

实验环境:

数据库:MySQL 5.0

机器硬件:

内存 3G 

CPU AMD双核4400+ 2.3G

首先建立一个简单的user表:

CREATE TABLE `user` (                                         

          `id` varchar(50) NOT NULL,                                  

          `seqid` bigint(20) NOT NULL auto_increment,                 

          `name` varchar(50) NOT NULL,                                 

          PRIMARY KEY (`seqid`)

        ) ENGINE=MyISAM DEFAULT CHARSET=utf8

一、普通插入

代码:

 1

数据库批量数据插入问题分析

Connection conn=source.getConnection();

 2

数据库批量数据插入问题分析

Statement s=conn.createStatement();

 3

数据库批量数据插入问题分析

String sql="";

 4

数据库批量数据插入问题分析

long start=System.currentTimeMillis();

 5

数据库批量数据插入问题分析

for(int i=0;i<100000;i++)

 6

数据库批量数据插入问题分析

{

 7

数据库批量数据插入问题分析

    sql="insert into user(id,name) value('"+(i+1)+"','chenxinhan')";

 8

数据库批量数据插入问题分析

    s.execute(sql);

 9

数据库批量数据插入问题分析

}

10

数据库批量数据插入问题分析

s.close();

11

数据库批量数据插入问题分析

conn.close();

12

数据库批量数据插入问题分析

long end=System.currentTimeMillis();

13

数据库批量数据插入问题分析

System.out.println("commonInsert()执行时间为:"+(end-start)+"ms"); 输出结果:

commonInsert()执行时间为:13828ms

二、普通插入+手动提交:setAutoCommit(false)、commit()

代码:  1

数据库批量数据插入问题分析

Connection conn=source.getConnection();

 2

数据库批量数据插入问题分析

conn.setAutoCommit(false);

 3

数据库批量数据插入问题分析

Statement s=conn.createStatement();

 4

数据库批量数据插入问题分析

String sql="";

 5

数据库批量数据插入问题分析

long start=System.currentTimeMillis();

 6

数据库批量数据插入问题分析

for(int i=0;i<100000;i++)

 7

数据库批量数据插入问题分析

{

 8

数据库批量数据插入问题分析

   sql="insert into user(id,name) value('"+(i+1)+"','chenxinhan')";

 9

数据库批量数据插入问题分析

   s.execute(sql);

10

数据库批量数据插入问题分析

}

11

数据库批量数据插入问题分析

conn.commit();

12

数据库批量数据插入问题分析

s.close();

13

数据库批量数据插入问题分析

conn.close();

14

数据库批量数据插入问题分析

long end=System.currentTimeMillis();

15

数据库批量数据插入问题分析

System.out.println("commonInsert()执行时间为:"+(end-start)+"ms"); 输出结果:

commonInsert()执行时间为:13813ms

对比分析:

可以看出,仅仅是这种方式的设置,对性能的影响并不大。

三、普通插入+手动提交+ prepareStatement方式

代码:  1

数据库批量数据插入问题分析

Connection conn=source.getConnection();

 2

数据库批量数据插入问题分析

        conn.setAutoCommit(false);

 3

数据库批量数据插入问题分析

        PreparedStatement ps=conn.prepareStatement("insert into user(id,name) value(?,?)");

 4

数据库批量数据插入问题分析

        long start=System.currentTimeMillis();

 5

数据库批量数据插入问题分析

        for(int i=0;i<100000;i++)

 6

数据库批量数据插入问题分析

        {

 7

数据库批量数据插入问题分析

            ps.setString(1,(i+1)+"");

 8

数据库批量数据插入问题分析

            ps.setString(2,"chenxinhan");

 9

数据库批量数据插入问题分析

            ps.execute();

10

数据库批量数据插入问题分析

        }

11

数据库批量数据插入问题分析

        conn.commit();

12

数据库批量数据插入问题分析

        ps.close();

13

数据库批量数据插入问题分析

        conn.close();

14

数据库批量数据插入问题分析

        long end=System.currentTimeMillis();

15

数据库批量数据插入问题分析

        System.out.println("prepareStatementInsert()执行时间为:"+(end-start)+"ms"); 输出结果:

prepareStatementInsert()执行时间为:12797ms

对比分析:

采用prepareStatement的方式确实可以提高一点性能,因为减少了数据库引擎解析优化SQL语句的时间,但是由于现在的插入语句太简单,所以性能提升不明显。

四、批量插入:addBatch、executeBatch

代码:  1

数据库批量数据插入问题分析

        Connection conn=source.getConnection();

 2

数据库批量数据插入问题分析

        conn.setAutoCommit(false);

 3

数据库批量数据插入问题分析

        Statement s=conn.createStatement();

 4

数据库批量数据插入问题分析

        String sql="";

 5

数据库批量数据插入问题分析

        long start=System.currentTimeMillis();

 6

数据库批量数据插入问题分析

        for(int j=0;j<100;j++)

 7

数据库批量数据插入问题分析

        {

 8

数据库批量数据插入问题分析

            for(int i=0;i<1000;i++)

 9

数据库批量数据插入问题分析

            {

10

数据库批量数据插入问题分析

                sql="insert into user(id,name) value('"+(i+1)+"','chenxinhan')";

11

数据库批量数据插入问题分析

                s.addBatch(sql);

12

数据库批量数据插入问题分析

            }

13

数据库批量数据插入问题分析

            s.executeBatch();

14

数据库批量数据插入问题分析

            conn.commit();

15

数据库批量数据插入问题分析

            s.clearBatch();

16

数据库批量数据插入问题分析

        }

17

数据库批量数据插入问题分析

        s.close();

18

数据库批量数据插入问题分析

        conn.close();

19

数据库批量数据插入问题分析

        long end=System.currentTimeMillis();

20

数据库批量数据插入问题分析

        System.out.println("batchInsert()执行时间为:"+(end-start)+"ms"); 输出结果:

batchInsert()执行时间为:13625ms

对比分析:

按道理,这种批处理的方式是要快些的,但是测试结果却不尽人意,有点不解,请高人拍砖。

五、批量插入:insert into tableName (x,xx,xxx) values(x,xx,xxx),(xx,xxx,xxxx)…,

代码:  1

数据库批量数据插入问题分析

Connection conn=source.getConnection();

 2

数据库批量数据插入问题分析

        conn.setAutoCommit(false);

 3

数据库批量数据插入问题分析

        Statement s=conn.createStatement();

 4

数据库批量数据插入问题分析

        StringBuilder sql=new StringBuilder("");

 5

数据库批量数据插入问题分析

        long start=System.currentTimeMillis();

 6

数据库批量数据插入问题分析

        for(int j=0;j<100;j++)

 7

数据库批量数据插入问题分析

        {

 8

数据库批量数据插入问题分析

            sql=new StringBuilder("");

 9

数据库批量数据插入问题分析

            sql.append("insert into user(id,name) values ");

10

数据库批量数据插入问题分析

            for(int i=0;i<1000;i++)

11

数据库批量数据插入问题分析

            {

12

数据库批量数据插入问题分析

                if(i==999)

13

数据库批量数据插入问题分析

                    sql.append("('").append(i+1).append("',").append("'cxh')");

14

数据库批量数据插入问题分析

                else

15

数据库批量数据插入问题分析

                    sql.append("('").append(i+1).append("',").append("'cxh'),");

16

数据库批量数据插入问题分析

            }

17

数据库批量数据插入问题分析

            s.execute(sql.toString());

18

数据库批量数据插入问题分析

            conn.commit();

19

数据库批量数据插入问题分析

        }

20

数据库批量数据插入问题分析

        s.close();

21

数据库批量数据插入问题分析

        conn.close();

22

数据库批量数据插入问题分析

        long end=System.currentTimeMillis();

23

数据库批量数据插入问题分析

        System.out.println("manyInsert()执行时间为:"+(end-start)+"ms"); 输出结果:

manyInsert()执行时间为:937ms

对比分析:

发现采用这种方式的批量插入性能提升最明显,有10倍以上的性能提升。所以这种方式是我推荐的批量插入方式!

六、多线程插入

在第五种方式的基础上采用多线程插入。

代码:  1

数据库批量数据插入问题分析

final Connection conn=source.getConnection();

 2

数据库批量数据插入问题分析

        for(int j=0;j<3;j++)

 3

数据库批量数据插入问题分析

        {

 4

数据库批量数据插入问题分析

            Thread t=new Thread(){

 5

数据库批量数据插入问题分析

                @Override

 6

数据库批量数据插入问题分析

                public void run() {

 7

数据库批量数据插入问题分析

                    try

 8

数据库批量数据插入问题分析

                    {

 9

数据库批量数据插入问题分析

                        long start=System.currentTimeMillis();

10

数据库批量数据插入问题分析

                        Statement s=conn.createStatement();

11

数据库批量数据插入问题分析

                        StringBuilder sql=new StringBuilder("");

12

数据库批量数据插入问题分析

                        for(int j=0;j<100;j++)

13

数据库批量数据插入问题分析

                        {

14

数据库批量数据插入问题分析

                            conn.setAutoCommit(false);

15

数据库批量数据插入问题分析

                            sql=new StringBuilder("");

16

数据库批量数据插入问题分析

                            sql.append("insert into user (id,name) values ");

17

数据库批量数据插入问题分析

                            for(int i=0;i<1000;i++)

18

数据库批量数据插入问题分析

                            {

19

数据库批量数据插入问题分析

                                if(i==999)

20

数据库批量数据插入问题分析

                                    sql.append("('").append(i+1).append("',").append("'cxh')");

21

数据库批量数据插入问题分析

                                else

22

数据库批量数据插入问题分析

                                    sql.append("('").append(i+1).append("',").append("'cxh'),");

23

数据库批量数据插入问题分析

                            }

24

数据库批量数据插入问题分析

                            s.execute(sql.toString());

25

数据库批量数据插入问题分析

                            conn.commit();

26

数据库批量数据插入问题分析

                        }

27

数据库批量数据插入问题分析

                        s.close();

28

数据库批量数据插入问题分析

                        long end=System.currentTimeMillis();

29

数据库批量数据插入问题分析

                        System.out.println("multiThreadBatchInsert()执行时间为:"+(end-start)+"ms");

30

数据库批量数据插入问题分析

                    }

31

数据库批量数据插入问题分析

                    catch(Exception e)

32

数据库批量数据插入问题分析

                    {

33

数据库批量数据插入问题分析

                        e.printStackTrace();

34

数据库批量数据插入问题分析

                    }

35

数据库批量数据插入问题分析

                }

36

数据库批量数据插入问题分析

            };

37

数据库批量数据插入问题分析

            t.start();

38

数据库批量数据插入问题分析

            //t.join();

39

数据库批量数据插入问题分析

        } 输出结果:

multiThreadBatchInsert()执行时间为:2437ms

multiThreadBatchInsert()执行时间为:2625ms

multiThreadBatchInsert()执行时间为:2703ms

注意:上面我采用的是三个线程插入30w条数据。

取最大时间为2703ms,较上面的937ms,基本还是三倍的时间。

所以发现此时多线程也解决不了批量数据插入问题。原因就是,这时候的性能瓶颈不是CPU,而是数据库!

七、InnoDB引擎和MyISAM引擎的比较

最后,分析一下,这两个引擎对批量数据插入的影响。

先建立user2数据表:

CREATE TABLE `user2` (                                         

          `id` varchar(50) NOT NULL,                                  

          `seqid` bigint(20) NOT NULL auto_increment,                 

          `name` varchar(50) NOT NULL,                                 

          PRIMARY KEY (`seqid`)

        ) ENGINE=InnoDB DEFAULT CHARSET=utf8

代码:  1

数据库批量数据插入问题分析

Connection conn=source.getConnection();

 2

数据库批量数据插入问题分析

        conn.setAutoCommit(false);

 3

数据库批量数据插入问题分析

        Statement s=conn.createStatement();

 4

数据库批量数据插入问题分析

        StringBuilder sql=new StringBuilder("");

 5

数据库批量数据插入问题分析

        long start=System.currentTimeMillis();

 6

数据库批量数据插入问题分析

        for(int j=0;j<100;j++)

 7

数据库批量数据插入问题分析

        {

 8

数据库批量数据插入问题分析

            sql=new StringBuilder("");

 9

数据库批量数据插入问题分析

            sql.append("insert into user2 (id,name) values ");

10

数据库批量数据插入问题分析

            for(int i=0;i<1000;i++)

11

数据库批量数据插入问题分析

            {

12

数据库批量数据插入问题分析

                if(i==999)

13

数据库批量数据插入问题分析

                    sql.append("('").append(i+1).append("',").append("'cxh')");

14

数据库批量数据插入问题分析

                else

15

数据库批量数据插入问题分析

                    sql.append("('").append(i+1).append("',").append("'cxh'),");

16

数据库批量数据插入问题分析

            }

17

数据库批量数据插入问题分析

            s.execute(sql.toString());

18

数据库批量数据插入问题分析

            conn.commit();

19

数据库批量数据插入问题分析

        }

20

数据库批量数据插入问题分析

        s.close();

21

数据库批量数据插入问题分析

        conn.close();

22

数据库批量数据插入问题分析

        long end=System.currentTimeMillis();

23

数据库批量数据插入问题分析

        System.out.println("manyInsert2()执行时间为:"+(end-start)+"ms"); 输出结果:

manyInsert2()执行时间为:3484ms

注意:第七项的代码和第五是一样的,除了数据表名称不同(user、user2)

但是,

InnoDB :3484ms

MyISAM:937ms

所以,MyISAM引擎对大数据量的插入性能较好。

总结:

对于大数据量的插入,建议使用insert into tableName (x,xx,xxx) values(x,xx,xxx),(xx,xxx,xxxx)…,的方式,引擎建议使用MyISAM引擎。

继续阅读