1. 程式人生 > >關於批量插入資料之我見(100萬級別的資料,mysql)

關於批量插入資料之我見(100萬級別的資料,mysql)

因前段時間去面試,問到如何高效向資料庫插入10萬條記錄,之前沒處理過類似問題,也沒看過相關資料,結果沒答上來,今天就查了些資料,總結出三種方法:

測試資料庫為mysql!!!

方法一:

  1. publicstaticvoid 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 + " s");  
  43.     }  

輸出時間:cast : 23 s

該方法目前測試是效率最高的方法!

方法二:

  1. publicstaticvoid 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 + " s");  
  23.     }  

注:註釋就沒有了,和上面類同,下面會有分析!

控制檯輸出:cast : 111 s

執行時間是上面方法的5倍!

方法三:

  1. publicstaticvoid insertBigData(SpringBatchHandler sbh) {  
  2.         Long begin = new Date().getTime();  
  3.         JdbcTemplate jdbcTemplate = sbh.getJdbcTemplate();  
  4.         finalint 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.             publicvoid setValues(PreparedStatement pst, int i)  
  9.                     throws SQLException {  
  10.                 pst.setLong(1, i);  
  11.                 pst.setInt(2, i);  
  12.             }  
  13.             // 返回更新的結果集條數
  14.             publicint getBatchSize() {  
  15.                 return count;  
  16.             }  
  17.         });  
  18.         Long end = new Date().getTime();  
  19.         System.out.println("cast : " + (end - begin) / 1000 + " s");  
  20.     }  

該方法採用的是spring batchUpdate執行,因效率問題,資料量只有1萬條!

執行時間:cast : 387 s

總結:方法一和方法二很類同,唯一不同的是方法一採用的是“insert into tb (...) values(...),(...)...;”的方式執行插入操作,

方法二則是“insert into tb (...) values (...);insert into tb (...) values (...);...”的方式,要不是測試,我也不知道兩者差別是如此之大!

當然,這個只是目前的測試,具體執行時間和步長也有很大關係!如過把步長改為100,可能方法就要幾分鐘了吧,這個可以自己測試哈。。。

方法三網上很推崇,不過,效率大家也都看到了,1萬條記錄,耗時6分鐘,可見其效率並不理想!而且方法三需要配置spring applicationContext環境才能應用!

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

剛才開始研究大資料方面的問題,以上也只是真實測試的結果,並不一定就是事實,有好的建議,大家請指正,謝謝!

相互學習,才能進步更快!

原始碼: