mysql5批处理_转关于mysql5.5 的批处理讨论(转载)
MySql的JDBC驅(qū)動不支持批量操作(已結(jié))
MySql連接的url中要加rewriteBatchedStatements參數(shù),例如
String?connectionUrl="jdbc:mysql://192.168.1.100:3306/test?rewriteBatchedStatements=true";
還要保證mysql JDBC驅(qū)的版本。MySql的JDBC驅(qū)動的批量插入操作性能是很優(yōu)秀的。
MySql的JDBC驅(qū)動,不是真正支持批量操作的,就算你在代碼中調(diào)用了批量操作的方法,MySql的JDBC驅(qū)動也是按照一般操作來處理的。
直覺告訴我,應(yīng)該是一些簡單的設(shè)置問題,事實上最后得到的結(jié)果也是如此的。
帶著解決這個疑惑的想法,依據(jù)大家之前得到的一些結(jié)果,信息,開始測試
工具:
eclipse-3.6, mysql-5.1.48, mysql-jdbc-driver 5.1.11, mysql workbench前面說過了,我直覺認(rèn)為代碼不會有問題,所以先著手改善mysql 的服務(wù)器配置,innodb的設(shè)置。改了幾個參數(shù),都沒有什么效果。加大了日志緩存,只是提高到7000多毫秒。最后甚至很多歪門邪道的設(shè)置都大膽用了,一度讓mysql 無法啟動。。。最終都收效甚微,這個步驟大概試了將近一個小時。
這條路看來是走不通了。。得尋找別的方法
冷靜下來想想,其實從代碼中應(yīng)該是可以發(fā)現(xiàn)些端倪
樓主的非batch代碼中,每次調(diào)用 execute() 其實是會通過網(wǎng)絡(luò)發(fā)送一條語句到服務(wù)器端的,是不會在客戶端排隊攢著的。
因為這個方法必須返回一個結(jié)果。它必然跟服務(wù)器發(fā)生了一次交互。
而在batch處理的代碼中,其addBatch 就是無返回值,它提供了一個可能就是在客戶端將語句緩存排隊攢著,最后executeBatch時才發(fā)送到服務(wù)器端。
用代碼可以證明,在batch處理方法的代碼中,在 executeBatch, 及 commit 方法執(zhí)行前,分別安插兩條打印時間語句:
Java代碼
System.out.println("before?executeBatch.?"+?(System.currentTimeMillis()-a)+"?ms");
prest.executeBatch();
System.out.println("before?commit.?"+?(System.currentTimeMillis()-a)+"?ms");
conn.commit();
System.out.println("before executeBatch. "+ (System.currentTimeMillis()-a)+" ms"); prest.executeBatch(); System.out.println("before commit. "+ (System.currentTimeMillis()-a)+" ms"); conn.commit();
在我機器上的結(jié)果是,
Java代碼
before?executeBatch.279ms
before?commit.7922ms
MySql批量插入10萬條記錄用時7923ms
before executeBatch. 279 ms before commit. 7922 ms MySql批量插入10萬條記錄用時7923 ms
說明客戶端在攢語句時,相當(dāng)?shù)目?#xff0c;279毫秒就完成了,但在 executeBatch 這個方法的調(diào)用過程中,花費了 7920? 減 去 279 的毫秒數(shù)。大部分都耗在這里了。 最后提交事務(wù)非常快,1毫秒而已
想想看,前邊說過,非batch和batch的處理幾乎是一樣的時間。
可不可以先假設(shè) batch 的方式與非batch一樣,每一條insrt語句事實上均是單獨發(fā)往服務(wù)器的呢?
瀏覽下源代碼吧。
好幾位兄弟都描述了源代碼,直接從那幾個類入手吧,事實上關(guān)鍵的類是這個 com.mysql.jdbc.PreparedStatement
先看了其中的 addBatch 方法,沒有任何問題,只是將語句添加進入一個 List 中保存。
那么 executeBatch 呢?
再貼一下吧, 關(guān)鍵看其中的這部分,順帶說一下, 這個mysql-jdbcdriver的源代碼是 5.1.13的
Java代碼
try{
clearWarnings();
if(!this.batchHasPlainStatements
&&this.connection.getRewriteBatchedStatements())?{
if(canRewriteAsMultiValueInsertAtSqlLevel())?{
returnexecuteBatchedInserts(batchTimeout);//執(zhí)行路徑之一
}
if(this.connection.versionMeetsMinimum(4,1,0)
&&?!this.batchHasPlainStatements
&&this.batchedArgs?!=null
&&this.batchedArgs.size()?>3/*?cost?of?option?setting?rt-wise?*/)?{
returnexecutePreparedBatchAsMultiStatement(batchTimeout);//執(zhí)行路徑之二
}
}
returnexecuteBatchSerially(batchTimeout);//執(zhí)行路徑之三
}finally{
clearBatch();
}
try { clearWarnings(); if (!this.batchHasPlainStatements && this.connection.getRewriteBatchedStatements()) { if (canRewriteAsMultiValueInsertAtSqlLevel()) { return executeBatchedInserts(batchTimeout); //執(zhí)行路徑之一 } if (this.connection.versionMeetsMinimum(4, 1, 0) && !this.batchHasPlainStatements && this.batchedArgs != null && this.batchedArgs.size() > 3 /* cost of option setting rt-wise */) { return executePreparedBatchAsMultiStatement(batchTimeout); //執(zhí)行路徑之二 } } return executeBatchSerially(batchTimeout); //執(zhí)行路徑之三 } finally { clearBatch(); }
其實最終,executeBatch 的執(zhí)行路徑有三種可能。代碼中我已標(biāo)出來
不小心按了提交了,繼續(xù)編輯此回復(fù)吧。代碼不算太復(fù)雜,但是有一個參數(shù)能幫助我們更快的確定mysql的batch工作機制,那就是
mysql jdbc driver 的connection url, 其中有一個參數(shù)是: rewriteBatchedStatements
完整的參數(shù)參考看這里:http://ftp.ntu.edu.tw/ftp/pub/MySQL/doc/refman/5.1/en/connector-j-reference-configuration-properties.html
rewriteBatchedStatements 參數(shù)默認(rèn)為false, 需要手工設(shè)置為true,設(shè)置方式大概像這樣:
Java代碼
String?connectionUrl="jdbc:mysql://192.168.1.100:3306/test?rewriteBatchedStatements=true";
String connectionUrl="jdbc:mysql://192.168.1.100:3306/test?rewriteBatchedStatements=true";
默認(rèn)時候,rewriteBatchedStatements=false時,執(zhí)行路徑會跳到 executeBatchSerially,此方法內(nèi)部將語句一條條發(fā)送,與非batch處理簡直一樣,所以慢,就在這里了。
當(dāng)設(shè)為 true時,會執(zhí)行executeBatchedInserts方法,事實上mysql支持這樣的插入語句
Sql代碼
insertintot_user(id,uname)values(1,'1'),?(2,'2'),?(3,'3')?....
insert into t_user(id,uname) values(1, '1'), (2,'2'), (3, '3') ....
所以,當(dāng)rewriteBatchedStatements=true時, 樓主的例子會被編譯為以上形式,當(dāng)然values里全是?, mysql 客戶端會對這些值添加參數(shù). 這樣的方式當(dāng)然就快很多了。
其實到現(xiàn)在還不太了解 batch 處理時,執(zhí)行計劃這個概念,不過我猜 mysql 可能并沒有緩存執(zhí)行計劃。而只是將這些語句組合起來了。
所以如果是這樣,他的機制與oracle可能是有所不同的,還不是達到最高效的機制,也許這就是開源與商業(yè)的區(qū)別吧。
我們?nèi)绻敫钊肓私?#xff0c;只能借助于一些服務(wù)器端監(jiān)視工具,sql分析工具了。
寫貼子過程斷斷續(xù)續(xù)給打擾了,本來還有一些可以寫更詳細的,就留給大家自己去探索了,包括,如果調(diào)用addBatch(String sql)后,則仍會按照 executeBatchSerially 方式執(zhí)行,包括何時執(zhí)行 executePreparedBatchAsMultiStatement,都可以繼續(xù)深入了解。
后記,當(dāng)使用 update 時,會執(zhí)行 executePreparedBatchAsMultiStatement,但是如果攢的語句太多,會導(dǎo)致 mysql 崩潰. 我的測試中10000條update不會有事,20000時,mysql 就崩掉了。
分享到:
2011-11-17 15:19
瀏覽 1569
分類:數(shù)據(jù)庫
評論
總結(jié)
以上是生活随笔為你收集整理的mysql5批处理_转关于mysql5.5 的批处理讨论(转载)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 串口通信 校验码_一文读懂S7-200
- 下一篇: csv导入mysql phpmyadmi