MySql 的批量操作,要加rewriteBatchedStatements參數


MySql 的批量操作,要加rewriteBatchedStatements參數

 

 

作者:趙磊

博客:http://elf8848.iteye.com

 

--------------------------------結論 ---------------------------------

MySql   非批量 10萬條記錄,                 5700條/秒

MySql   批量(batch) 10萬條記錄,         62500條/秒

oracle   非批量插入10萬條記錄,            4464 條/秒

oracle   批量 (batch)插入10萬條記錄,   27778 條/秒

 

注:以上測試都是在插入10萬條數據完成之后,一次性提交事務(對性能影響很大,占了很大便宜)。

另有一篇文章,說明提交事務的次數對insert性能的影響:《MySql 插入(insert)性能測試 》 

 

 

 

MySql的JDBC連接的url中要加rewriteBatchedStatements參數,並保證5.1.13以上版本的驅動,才能實現高性能的批量插入。

例如: String connectionUrl="jdbc:mysql://192.168.1.100:3306/test?rewriteBatchedStatements=true" 

還要保證Mysql JDBC驅的版本。MySql的JDBC驅動的批量插入操作性能是很優秀的。

 

 

 

Mysql JDBC驅動,各個版本測試結果:

 

MySql JDBC 驅動版本號        插入10萬條數據用時
5.0.8 加了rewriteBatchedStatements參數,沒有提高還是17.4秒
5.1.7 加了rewriteBatchedStatements參數,沒有提高還是17.4秒
5.1.13 加了rewriteBatchedStatements參數,插入速度提高到1.6秒

 

 

 

 

關於rewriteBatchedStatements參數,Mysql官方的說明:

Should the driver use multiqueries (irregardless of the setting of "allowMultiQueries") as well as rewriting of prepared statements for INSERT into multi-value inserts when executeBatch() is called? Notice that this has the potential for SQL injection if using plain java.sql.Statements and your code doesn't sanitize input correctly. Notice that for prepared statements, server-side prepared statements can not currently take advantage of this rewrite option, and that if you don't specify stream lengths when using PreparedStatement.set*Stream(), the driver won't be able to determine the optimum number of parameters per batch and you might receive an error from the driver that the resultant packet is too large. Statement.getGeneratedKeys() for these rewritten statements only works when the entire batch includes INSERT statements.

 

請參見:http://dev.mysql.com/doc/refman/5.1/en/connector-j-reference-configuration-properties.html

 

-------------------------事情的起因 ---------------------------------


原貼是《使用DBCP 數據庫連接池遇到的兩個比較懷疑的問題》 
http://www.iteye.com/topic/768416 

帖子是問連接池問題的,主要是使用連接池向MySql插入大量數據的事兒,有很多javaEye的朋友讓作者使用JDBC的批量操作來提高大量插入數據的性能。

mercyblitz 寫道
elf8848 寫道
前面有多位朋友提出,讓樓主使用 jdbc的批量操作,就是PreparedStatement 類上的addBatch(),executeBatch()方法。 

在這里要提醒一下大家,MySql的JDBC驅動,是不支持批量操作的,就算你在代碼中調用了批量操作的方法,MySql的JDBC驅動,也是按一般insert操作來處理的。 

同樣Fetch Size特性MySql的JDBC驅動也不支持。而Oracle的JDBC驅動是都支持的。 

樓主使用的是Mysql數據庫, 不要指望通過批處理來提高 性能了。


請不要想當然,建議你去看一下MySQL JDBC的源代碼! 

MySQL JDBC驅動在發送命令是,都是傳遞一個數組的String類型,然后轉化為一個二維byte數組。 

如果是一條的Statement的話,這個String數組只有一個元素,如果是Batch的話,則有相應個元素。 

最后發送IO命令。不清楚你的結論是哪里來的?


我在這里重復的提醒大家: 
MySql的JDBC驅動,不是真正支持批量操作的,就算你在代碼中調用了批量操作的方法,MySql的JDBC驅動也是按照一般操作來處理的。 
這不是什么重大發現,也不是什么新消息,是老調重彈,如果你使用Mysql數據庫不要寄希望於通過JDBC批量操作來提高大量插入數據的性能,起碼目前的MySql的JDBC驅動是這樣的。 

 

 

--------------------------------- 測試環境 ---------------------------------

 

測試機:筆記本電腦ThinkPad T400

操作系統:Windows XP 

CPU:P8600 2.4G

內存:2G 

IP:192.168.10.124

 

數據庫服務器:筆記本ThinkPad T400

操作系統:虛擬機Windows 2003 

內存:操作系統分配了500M (真可憐啊)

IP:192.168.10.139

 

數據庫服務器上安裝有MySql5.0.18 ,Oracle10G,都是默認安裝。

 

JDBC驅動版本: 

MySql : mysql-connector-java-5.0.8 

Oracle : ojdbc6.jar  (之前使用ojdbc14.jar批量插入10萬條,實際只插入了3萬多條,其它的丟失了,換ojdbc6.jar后,一次commit插入100萬條也沒有問題)

 

表只有兩個字段:

id int

uname varchar(10)

innoDB引擎

 

 

 

---------------------------------測試結果: ---------------------------------

 

  mysql非批量插入10萬條記錄

 mysql批量插入10萬條記錄

(JDBC的URL中未加參數)

oracle非批量插入10萬條記錄  oracle批量插入10萬條記錄  
第1次  17437 ms  17437 ms  22391 ms  360 ms
第2次  17422 ms  17562 ms  22297 ms  328 ms
第3次  17046 ms  17140 ms  22703 ms  359 ms 


這里通過一個點也可以看出來Mysql批量與非批量性能是一樣。

oracle的JDBC實現的批量操作的性能十分優秀。

 

---------------------------------測試方法: ---------------------------------

 

下面是測試代碼:

Java代碼   收藏代碼
  1. package jdbc2;  
  2. import java.sql.Connection;  
  3. import java.sql.DriverManager;  
  4. import java.sql.PreparedStatement;  
  5. import java.sql.SQLException;  
  6.   
  7. public class Mysql {  
  8.     public static void main(String[] args) {  
  9.         test_mysql();  
  10.         //test_mysql_batch();  
  11.         //test_oracle();  
  12.         //test_oracle_batch();  
  13.     }  
  14.     /** 
  15.      * mysql非批量插入10萬條記錄 
  16.      * 第1次:17437 ms 
  17.      * 第2次:17422 ms 
  18.      * 第3次:17046 ms 
  19.      */  
  20.     public static void test_mysql(){  
  21.         String url="jdbc:mysql://192.168.10.139:3306/test";  
  22.         String userName="root";  
  23.         String password="1234";  
  24.         Connection conn=null;  
  25.         try {        
  26.               Class.forName("com.mysql.jdbc.Driver");        
  27.               conn =  DriverManager.getConnection(url, userName, password);        
  28.               conn.setAutoCommit(false);        
  29.               String sql = "insert into t_user(id,uname) values(?,?)";        
  30.               PreparedStatement prest = conn.prepareStatement(sql);        
  31.               long a=System.currentTimeMillis();  
  32.               for(int x = 0; x < 100000; x++){        
  33.                  prest.setInt(1, x);        
  34.                  prest.setString(2"張三");        
  35.                  prest.execute();  
  36.               }        
  37.               conn.commit();        
  38.               long b=System.currentTimeMillis();  
  39.               System.out.println("MySql非批量插入10萬條記錄用時"+ (b-a)+" ms");  
  40.         } catch (Exception ex) {  
  41.             ex.printStackTrace();  
  42.         }finally{  
  43.             try {  
  44.                 if(conn!=null)conn.close();  
  45.             } catch (SQLException e) {  
  46.                 e.printStackTrace();  
  47.             }     
  48.         }  
  49.     }  
  50.     /** 
  51.      * mysql批量插入10萬條記錄(未加rewriteBatchedStatements參數)   ,加了參數后是1600ms左右 
  52.      * 第1次:17437 ms 
  53.      * 第2次:17562 ms 
  54.      * 第3次:17140 ms 
  55.      */  
  56.     public static void test_mysql_batch(){  
  57.         //String url="jdbc:mysql://192.168.10.139:3306/test";  
  58. <p style="margin: 0.0px 0.0px 0.0px 0.0px; color: #3b3df5;"><span style="font-family: Verdana,Arial,Helvetica,sans-serif; color: #000000;">     String url="jdbc:mysql://127.0.0.1:3306/dev?rewriteBatchedStatements=true";</span>  
  59.   
  60.   
  61. </p>  
  62.   
  63.   
  64.         String userName="root";  
  65.         String password="1234";  
  66.         Connection conn=null;  
  67.         try {        
  68.             Class.forName("com.mysql.jdbc.Driver");        
  69.             conn =  DriverManager.getConnection(url, userName, password);        
  70.             conn.setAutoCommit(false);        
  71.             String sql = "insert into t_user(id,uname) values(?,?)";        
  72.             PreparedStatement prest = conn.prepareStatement(sql);        
  73.             long a=System.currentTimeMillis();  
  74.             for(int x = 0; x < 100000; x++){        
  75.                 prest.setInt(1, x);        
  76.                 prest.setString(2"張三");        
  77.                 prest.addBatch();      
  78.             }        
  79.             prest.executeBatch();        
  80.             conn.commit();        
  81.             long b=System.currentTimeMillis();  
  82.             System.out.println("MySql批量插入10萬條記錄用時"+ (b-a)+" ms");  
  83.         } catch (Exception ex) {  
  84.             ex.printStackTrace();  
  85.         }finally{  
  86.             try {  
  87.                 if(conn!=null)conn.close();  
  88.             } catch (SQLException e) {  
  89.                 e.printStackTrace();  
  90.             }     
  91.         }  
  92.     }  
  93.     /** 
  94.      * oracle非批量插入10萬條記錄 
  95.      * 第1次:22391 ms 
  96.      * 第2次:22297 ms 
  97.      * 第3次:22703 ms 
  98.      */  
  99.     public static void test_oracle(){  
  100.         String url="jdbc:oracle:thin:@192.168.10.139:1521:orcl";  
  101.         String userName="scott";  
  102.         String password="tiger";      
  103.         Connection conn=null;  
  104.         try {        
  105.             Class.forName("oracle.jdbc.OracleDriver");        
  106.             conn =  DriverManager.getConnection(url, userName, password);        
  107.             conn.setAutoCommit(false);        
  108.             String sql = "insert into t_user(id,uname) values(?,?)";        
  109.             PreparedStatement prest = conn.prepareStatement(sql);        
  110.             long a=System.currentTimeMillis();  
  111.             for(int x = 0; x < 100000; x++){        
  112.                 prest.setInt(1, x);        
  113.                 prest.setString(2"張三");        
  114.                 prest.execute();  
  115.             }  
  116.             conn.commit();        
  117.             long b=System.currentTimeMillis();  
  118.             System.out.println("Oracle非批量插入10萬記錄用時"+ (b-a)+" ms");  
  119.             conn.close();      
  120.         } catch (Exception ex) {  
  121.             ex.printStackTrace();  
  122.         }finally{  
  123.             try {  
  124.                 if(conn!=null)conn.close();  
  125.             } catch (SQLException e) {  
  126.                 e.printStackTrace();  
  127.             }     
  128.         }  
  129.     }  
  130.     /** 
  131.      * oracle批量插入10萬條記錄 
  132.      * 第1次:360 ms 
  133.      * 第2次:328 ms 
  134.      * 第3次:359 ms 
  135.      */  
  136.     public static void test_oracle_batch(){  
  137.         String url="jdbc:oracle:thin:@192.168.10.139:1521:orcl";  
  138.         String userName="scott";  
  139.         String password="tiger";      
  140.         Connection conn=null;  
  141.         try {        
  142.             Class.forName("oracle.jdbc.OracleDriver");        
  143.             conn =  DriverManager.getConnection(url, userName, password);        
  144.             conn.setAutoCommit(false);        
  145.             String sql = "insert into t_user(id,uname) values(?,?)";        
  146.             PreparedStatement prest = conn.prepareStatement(sql);        
  147.             long a=System.currentTimeMillis();  
  148.             for(int x = 0; x < 100000; x++){        
  149.                 prest.setInt(1, x);        
  150.                 prest.setString(2"張三");        
  151.                 prest.addBatch();  
  152.             }  
  153.             prest.executeBatch();        
  154.             conn.commit();        
  155.             long b=System.currentTimeMillis();  
  156.             System.out.println("Oracle批量插入10萬記錄用時"+ (b-a)+" ms");  
  157.             conn.close();      
  158.         } catch (Exception ex) {  
  159.             ex.printStackTrace();  
  160.         }finally{  
  161.             try {  
  162.                 if(conn!=null)conn.close();  
  163.             } catch (SQLException e) {  
  164.                 e.printStackTrace();  
  165.             }     
  166.         }  
  167.     }  
  168. }  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM