时间:2021-07-01 10:21:17 帮助过:23人阅读
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
一、普通插入
代码:
 Connection conn=source.getConnection();
Connection conn=source.getConnection(); Statement s=conn.createStatement();
Statement s=conn.createStatement(); String sql="";
String sql=""; long start=System.currentTimeMillis();
long start=System.currentTimeMillis(); for(int i=0;i<100000;i++)
for(int i=0;i<100000;i++) {
{ sql="insert into user(id,name) value(‘"+(i+1)+"‘,‘chenxinhan‘)";
    sql="insert into user(id,name) value(‘"+(i+1)+"‘,‘chenxinhan‘)"; s.execute(sql);
    s.execute(sql); }
} s.close();
s.close(); conn.close();
conn.close(); long end=System.currentTimeMillis();
long end=System.currentTimeMillis(); System.out.println("commonInsert()执行时间为:"+(end-start)+"ms");
System.out.println("commonInsert()执行时间为:"+(end-start)+"ms");
输出结果:
commonInsert()执行时间为:13828ms
二、普通插入+手动提交:setAutoCommit(false)、commit()
代码:
 Connection conn=source.getConnection();
Connection conn=source.getConnection(); conn.setAutoCommit(false);
conn.setAutoCommit(false); Statement s=conn.createStatement();
Statement s=conn.createStatement(); String sql="";
String sql=""; long start=System.currentTimeMillis();
long start=System.currentTimeMillis(); for(int i=0;i<100000;i++)
for(int i=0;i<100000;i++) {
{ sql="insert into user(id,name) value(‘"+(i+1)+"‘,‘chenxinhan‘)";
   sql="insert into user(id,name) value(‘"+(i+1)+"‘,‘chenxinhan‘)"; s.execute(sql);
   s.execute(sql); }
} conn.commit();
conn.commit(); s.close();
s.close(); conn.close();
conn.close(); long end=System.currentTimeMillis();
long end=System.currentTimeMillis(); System.out.println("commonInsert()执行时间为:"+(end-start)+"ms");
System.out.println("commonInsert()执行时间为:"+(end-start)+"ms");
输出结果:
commonInsert()执行时间为:13813ms
对比分析:
可以看出,仅仅是这种方式的设置,对性能的影响并不大。
三、普通插入+手动提交+ prepareStatement方式
代码:
 Connection conn=source.getConnection();
Connection conn=source.getConnection(); conn.setAutoCommit(false);
        conn.setAutoCommit(false); PreparedStatement ps=conn.prepareStatement("insert into user(id,name) value(?,?)");
        PreparedStatement ps=conn.prepareStatement("insert into user(id,name) value(?,?)"); long start=System.currentTimeMillis();
        long start=System.currentTimeMillis(); for(int i=0;i<100000;i++)
        for(int i=0;i<100000;i++) {
        { ps.setString(1,(i+1)+"");
            ps.setString(1,(i+1)+""); ps.setString(2,"chenxinhan");
            ps.setString(2,"chenxinhan"); ps.execute();
            ps.execute(); }
        } conn.commit();
        conn.commit(); ps.close();
        ps.close(); conn.close();
        conn.close(); long end=System.currentTimeMillis();
        long end=System.currentTimeMillis(); System.out.println("prepareStatementInsert()执行时间为:"+(end-start)+"ms");
        System.out.println("prepareStatementInsert()执行时间为:"+(end-start)+"ms");
输出结果:
prepareStatementInsert()执行时间为:12797ms
对比分析:
采用prepareStatement的方式确实可以提高一点性能,因为减少了数据库引擎解析优化SQL语句的时间,但是由于现在的插入语句太简单,所以性能提升不明显。
四、批量插入:addBatch、executeBatch
代码:
 Connection conn=source.getConnection();
        Connection conn=source.getConnection(); conn.setAutoCommit(false);
        conn.setAutoCommit(false); Statement s=conn.createStatement();
        Statement s=conn.createStatement(); String sql="";
        String sql=""; long start=System.currentTimeMillis();
        long start=System.currentTimeMillis(); for(int j=0;j<100;j++)
        for(int j=0;j<100;j++) {
        { for(int i=0;i<1000;i++)
            for(int i=0;i<1000;i++) {
            { sql="insert into user(id,name) value(‘"+(i+1)+"‘,‘chenxinhan‘)";
                sql="insert into user(id,name) value(‘"+(i+1)+"‘,‘chenxinhan‘)"; s.addBatch(sql);
                s.addBatch(sql); }
            } s.executeBatch();
            s.executeBatch(); conn.commit();
            conn.commit(); s.clearBatch();
            s.clearBatch(); }
        } s.close();
        s.close(); conn.close();
        conn.close(); long end=System.currentTimeMillis();
        long end=System.currentTimeMillis(); System.out.println("batchInsert()执行时间为:"+(end-start)+"ms");
        System.out.println("batchInsert()执行时间为:"+(end-start)+"ms");
输出结果:
batchInsert()执行时间为:13625ms
对比分析:
按道理,这种批处理的方式是要快些的,但是测试结果却不尽人意,有点不解,请高人拍砖。
五、批量插入:insert into tableName (x,xx,xxx) values(x,xx,xxx),(xx,xxx,xxxx)…,
代码:
 Connection conn=source.getConnection();
Connection conn=source.getConnection(); conn.setAutoCommit(false);
        conn.setAutoCommit(false); Statement s=conn.createStatement();
        Statement s=conn.createStatement(); StringBuilder sql=new StringBuilder("");
        StringBuilder sql=new StringBuilder(""); long start=System.currentTimeMillis();
        long start=System.currentTimeMillis(); for(int j=0;j<100;j++)
        for(int j=0;j<100;j++) {
        { sql=new StringBuilder("");
            sql=new StringBuilder(""); sql.append("insert into user(id,name) values ");
            sql.append("insert into user(id,name) values "); for(int i=0;i<1000;i++)
            for(int i=0;i<1000;i++) {
            { if(i==999)
                if(i==999) sql.append("(‘").append(i+1).append("‘,").append("‘cxh‘)");
                    sql.append("(‘").append(i+1).append("‘,").append("‘cxh‘)"); else
                else sql.append("(‘").append(i+1).append("‘,").append("‘cxh‘),");
                    sql.append("(‘").append(i+1).append("‘,").append("‘cxh‘),"); }
            } s.execute(sql.toString());
            s.execute(sql.toString()); conn.commit();
            conn.commit(); }
        } s.close();
        s.close(); conn.close();
        conn.close(); long end=System.currentTimeMillis();
        long end=System.currentTimeMillis(); System.out.println("manyInsert()执行时间为:"+(end-start)+"ms");
        System.out.println("manyInsert()执行时间为:"+(end-start)+"ms");
输出结果:
manyInsert()执行时间为:937ms
对比分析:
发现采用这种方式的批量插入性能提升最明显,有10倍以上的性能提升。所以这种方式是我推荐的批量插入方式!
六、多线程插入
在第五种方式的基础上采用多线程插入。
代码:
 final Connection conn=source.getConnection();
final Connection conn=source.getConnection(); for(int j=0;j<3;j++)
        for(int j=0;j<3;j++) {
        { Thread t=new Thread(){
            Thread t=new Thread(){ @Override
                @Override public void run() {
                public void run() { try
                    try {
                    { long start=System.currentTimeMillis();
                        long start=System.currentTimeMillis(); Statement s=conn.createStatement();
                        Statement s=conn.createStatement(); StringBuilder sql=new StringBuilder("");
                        StringBuilder sql=new StringBuilder(""); for(int j=0;j<100;j++)
                        for(int j=0;j<100;j++) {
                        { conn.setAutoCommit(false);
                            conn.setAutoCommit(false); sql=new StringBuilder("");
                            sql=new StringBuilder(""); sql.append("insert into user (id,name) values ");
                            sql.append("insert into user (id,name) values "); for(int i=0;i<1000;i++)
                            for(int i=0;i<1000;i++) {
                            { if(i==999)
                                if(i==999) sql.append("(‘").append(i+1).append("‘,").append("‘cxh‘)");
                                    sql.append("(‘").append(i+1).append("‘,").append("‘cxh‘)"); else
                                else sql.append("(‘").append(i+1).append("‘,").append("‘cxh‘),");
                                    sql.append("(‘").append(i+1).append("‘,").append("‘cxh‘),"); }
                            } s.execute(sql.toString());
                            s.execute(sql.toString()); conn.commit();
                            conn.commit(); }
                        } s.close();
                        s.close(); long end=System.currentTimeMillis();
                        long end=System.currentTimeMillis(); System.out.println("multiThreadBatchInsert()执行时间为:"+(end-start)+"ms");
                        System.out.println("multiThreadBatchInsert()执行时间为:"+(end-start)+"ms"); }
                    } catch(Exception e)
                    catch(Exception e) {
                    { e.printStackTrace();
                        e.printStackTrace(); }
                    } }
                } };
            }; t.start();
            t.start(); //t.join();
            //t.join(); }
        }
输出结果:
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
代码:
 Connection conn=source.getConnection();
Connection conn=source.getConnection(); conn.setAutoCommit(false);
        conn.setAutoCommit(false); Statement s=conn.createStatement();
        Statement s=conn.createStatement(); StringBuilder sql=new StringBuilder("");
        StringBuilder sql=new StringBuilder(""); long start=System.currentTimeMillis();
        long start=System.currentTimeMillis(); for(int j=0;j<100;j++)
        for(int j=0;j<100;j++) {
        { sql=new StringBuilder("");
            sql=new StringBuilder(""); sql.append("insert into user2 (id,name) values ");
            sql.append("insert into user2 (id,name) values "); for(int i=0;i<1000;i++)
            for(int i=0;i<1000;i++) {
            { if(i==999)
                if(i==999) sql.append("(‘").append(i+1).append("‘,").append("‘cxh‘)");
                    sql.append("(‘").append(i+1).append("‘,").append("‘cxh‘)"); else
                else sql.append("(‘").append(i+1).append("‘,").append("‘cxh‘),");
                    sql.append("(‘").append(i+1).append("‘,").append("‘cxh‘),"); }
            } s.execute(sql.toString());
            s.execute(sql.toString()); conn.commit();
            conn.commit(); }
        } s.close();
        s.close(); conn.close();
        conn.close(); long end=System.currentTimeMillis();
        long end=System.currentTimeMillis(); System.out.println("manyInsert2()执行时间为:"+(end-start)+"ms");
        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引擎。
友情提醒:本博文章欢迎转载,但请注明出处:陈新汉
数据库批量数据插入问题分析
标签:varchar log blocks 结果 user 解决 on() 对比分析 硬件