关于批量插入数据之我见(100万级别的数据,mysql) (转)

因前段时间去面试,问到如何高效向数据库插入10万条记录,之前没处理过类似问题,也没看过相关资料,结果没答上来,今天就查了些资料,总结出三种方法:

测试数据库为MySQL!!!

方法一:

  1. public static void insert() {  
  2.         // 开时时间  
  3.         Long begin = new Date().getTime();  
  4.         // sql前缀  
  5.         String prefix = "INSERT INTO tb_big_data (count, create_time, random) VALUES ";  
  6.         try {  
  7.             // 保存sql后缀  
  8.             StringBuffer suffix = new StringBuffer();  
  9.             // 设置事务为非自动提交  
  10.             conn.setAutoCommit(false);  
  11.             // Statement st = conn.createStatement();  
  12.             // 比起st,pst会更好些  
  13.             PreparedStatement pst = conn.prepareStatement("");  
  14.             // 外层循环,总提交事务次数  
  15.             for (int i = 1; i <= 100; i++) {  
  16.                 // 第次提交步长  
  17.                 for (int j = 1; j <= 10000; j++) {  
  18.                     // 构建sql后缀  
  19.                     suffix.append("(" + j * i + ", SYSDATE(), " + i * j  
  20.                             * Math.random() + "),");  
  21.                 }  
  22.                 // 构建完整sql  
  23.                 String sql = prefix + suffix.substring(0, suffix.length() - 1);  
  24.                 // 添加执行sql  
  25.                 pst.addBatch(sql);  
  26.                 // 执行操作  
  27.                 pst.executeBatch();  
  28.                 // 提交事务  
  29.                 conn.commit();  
  30.                 // 清空上一次添加的数据  
  31.                 suffix = new StringBuffer();  
  32.             }  
  33.             // 头等连接  
  34.             pst.close();  
  35.             conn.close();  
  36.         } catch (SQLException e) {  
  37.             e.printStackTrace();  
  38.         }  
  39.         // 结束时间  
  40.         Long end = new Date().getTime();  
  41.         // 耗时  
  42.         System.out.println("cast : " + (end - begin) / 1000 + " ms");  
  43.     }  
public static void insert() {
        // 开时时间
        Long begin = new Date().getTime();
        // sql前缀
        String prefix = "INSERT INTO tb_big_data (count, create_time, random) VALUES ";
        try {
            // 保存sql后缀
            StringBuffer suffix = new StringBuffer();
            // 设置事务为非自动提交
            conn.setAutoCommit(false);
            // Statement st = conn.createStatement();
            // 比起st,pst会更好些
            PreparedStatement pst = conn.prepareStatement("");
            // 外层循环,总提交事务次数
            for (int i = 1; i <= 100; i++) {
                // 第次提交步长
                for (int j = 1; j <= 10000; j++) {
                    // 构建sql后缀
                    suffix.append("(" + j * i + ", SYSDATE(), " + i * j
                            * Math.random() + "),");
                }
                // 构建完整sql
                String sql = prefix + suffix.substring(0, suffix.length() - 1);
                // 添加执行sql
                pst.addBatch(sql);
                // 执行操作
                pst.executeBatch();
                // 提交事务
                conn.commit();
                // 清空上一次添加的数据
                suffix = new StringBuffer();
            }
            // 头等连接
            pst.close();
            conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        // 结束时间
        Long end = new Date().getTime();
        // 耗时
        System.out.println("cast : " + (end - begin) / 1000 + " ms");
    }


输出时间:cast : 23 ms

该方法目前测试是效率最高的方法!




方法二:

  1. public static void insertRelease() {  
  2.         Long begin = new Date().getTime();  
  3.         String sql = "INSERT INTO tb_big_data (count, create_time, random) VALUES (?, SYSDATE(), ?)";  
  4.         try {  
  5.             conn.setAutoCommit(false);  
  6.             PreparedStatement pst = conn.prepareStatement(sql);  
  7.             for (int i = 1; i <= 100; i++) {  
  8.                 for (int k = 1; k <= 10000; k++) {  
  9.                     pst.setLong(1, k * i);  
  10.                     pst.setLong(2, k * i);  
  11.                     pst.addBatch();  
  12.                 }  
  13.                 pst.executeBatch();  
  14.                 conn.commit();  
  15.             }  
  16.             pst.close();  
  17.             conn.close();  
  18.         } catch (SQLException e) {  
  19.             e.printStackTrace();  
  20.         }  
  21.         Long end = new Date().getTime();  
  22.         System.out.println("cast : " + (end - begin) / 1000 + " ms");  
  23.     }  
public static void insertRelease() {
        Long begin = new Date().getTime();
        String sql = "INSERT INTO tb_big_data (count, create_time, random) VALUES (?, SYSDATE(), ?)";
        try {
            conn.setAutoCommit(false);
            PreparedStatement pst = conn.prepareStatement(sql);
            for (int i = 1; i <= 100; i++) {
                for (int k = 1; k <= 10000; k++) {
                    pst.setLong(1, k * i);
                    pst.setLong(2, k * i);
                    pst.addBatch();
                }
                pst.executeBatch();
                conn.commit();
            }
            pst.close();
            conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        Long end = new Date().getTime();
        System.out.println("cast : " + (end - begin) / 1000 + " ms");
    }

注:注释就没有了,和上面类同,下面会有分析!

控制台输出:cast : 111 ms

执行时间是上面方法的5倍!



方法三:

  1. public static void insertBigData(SpringBatchHandler sbh) {  
  2.         Long begin = new Date().getTime();  
  3.         JdbcTemplate jdbcTemplate = sbh.getJdbcTemplate();  
  4.         final int count = 10000;  
  5.         String sql = "INSERT INTO tb_big_data (count, create_time, random) VALUES (?, SYSDATE(), ?)";  
  6.         jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {  
  7.             // 为prepared statement设置参数。这个方法将在整个过程中被调用的次数  
  8.             public void setValues(PreparedStatement pst, int i)  
  9.                     throws SQLException {  
  10.                 pst.setLong(1, i);  
  11.                 pst.setInt(2, i);  
  12.             }  
  13.   
  14.             // 返回更新的结果集条数  
  15.             public int getBatchSize() {  
  16.                 return count;  
  17.             }  
  18.         });  
  19.         Long end = new Date().getTime();  
  20.         System.out.println("cast : " + (end - begin) / 1000 + " ms");  
  21.     }  
public static void insertBigData(SpringBatchHandler sbh) {
        Long begin = new Date().getTime();
        JdbcTemplate jdbcTemplate = sbh.getJdbcTemplate();
        final int count = 10000;
        String sql = "INSERT INTO tb_big_data (count, create_time, random) VALUES (?, SYSDATE(), ?)";
        jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
            // 为prepared statement设置参数。这个方法将在整个过程中被调用的次数
            public void setValues(PreparedStatement pst, int i)
                    throws SQLException {
                pst.setLong(1, i);
                pst.setInt(2, i);
            }

            // 返回更新的结果集条数
            public int getBatchSize() {
                return count;
            }
        });
        Long end = new Date().getTime();
        System.out.println("cast : " + (end - begin) / 1000 + " ms");
    }

该方法采用的是spring batchUpdate执行,因效率问题,数据量只有1万条!

执行时间:cast : 387 ms





总结:方法一和方法二很类同,唯一不同的是方法一采用的是“insert into tb (...) values(...),(...)...;”的方式执行插入操作,

方法二则是“insert into tb (...) values (...);insert into tb (...) values (...);...”的方式,要不是测试,我也不知道两者差别是如此之大!

当然,这个只是目前的测试,具体执行时间和步长也有很大关系!如过把步长改为100,可能方法就要几分钟了吧,这个可以自己测试哈。。。

方法三网上很推崇,不过,效率大家也都看到了,1万条记录,耗时6分钟,可见其效率并不理想!而且方法三需要配置spring applicationContext环境才能应用!

不过,方法三在ssh/spring-mvc中可用性还是很高的!


刚才开始研究大数据方面的问题,以上也只是真实测试的结果,并不一定就是事实,有好的建议,大家请指正,谢谢!

相互学习,才能进步更快!


晚点会把源码发上来,大家可以直接去下载测试!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值