Re: [問題] 如何快速插入大量資料到MySQL
※ 引述《asklove (問愛)》之銘言:
: 我現在在寫一個JAVA程式,要同步異質平台的資料
: 簡單的說就是要把資料從 Oracle 拋到 MySQL
: 目前使用 ArrayList、prepareStatement(在這裡爬文爬到的方法,效能有改善很多)、
: addBatch、executeBatch 之類的方法
: 每一筆資料都是一個 insert into 的 SQL
: 先用 addBatch 丟到 prepareStatement,最後執行一次 executeBatch
: 記憶體的部分,暫時使用批次撈取/匯入的方式解決
: 另外同時也匯出.CSV檔以做為備份用(有考慮順便產生 sql 檔,那是後話暫且不提)
: 但我發現它在插入 MySQL 時的速度很慢
: 例如我有一天的資料量是 384329 筆,用這支 JAVA來執行 Insert 大約要花上20分鐘
: 但用 phpMyAdmin 匯入 CSV 檔卻在2分鐘以內就完成,差別太大了!
: 我一時之間想不到問題所在,不知道是我不會用還是....
: 請問還有改善的空間嗎?
: 還是說 JAVA 的能力就只能到這樣,沒辦法比 PHP 和 Apache 更快呢?
^^^^^^
突然有一種,公堂之上為甚麼要提人家老母的感覺
(Apache:棍! 躺著也中槍)
理論上,這跟 Java 是沒有關係的
應該說,如果你要講上頭這句話,那前提是你用 PHP 執行相同的 sql 語法
問題是,你不是阿... [怒指]
如果測試條件不是相同 or 接近的話
你怎麼能夠大辣辣的講 or 批判一些你不確定的事情?
用我個人內心的標準,還想指控你沒有認真作功課就上來發問 XD
請看一下 phpmyadmin 的資料匯出 sql 語法的內容
他是多筆資料塞成一個 sql 語法
同理,我們絕對有理由相信,phpmyadmin 處理 .csv 也是同樣方法
撇開 PrepareStatement 的問題,我的測試程式跑出來的結果
用一筆資料一個 insert 語法
跟所有資料一個 insert 語法
執行速度差不多也是十倍左右,跟你報出來的數據差不多
我用 PHP 跑,也差不多是這個比例
: 附帶一提,我使用的 JDBC Driver 是 mysql-connector-java-5.1.8-bin.jar
我對 PrepareStatement 不太熟 [炸]
還得感謝原 po 給我這個機會上台領獎... (阿? 拿錯講稿了 [炸])
不然我還不知道
其實 PrepareStatement 的執行速度根本沒有比較快...
(至少在 MySQL 的 JDBC driver 是這樣 Orz)
以下是不太嚴謹的測試程式 & 數據,僅供參考 XD
btw... 我也是用相同 JDBC driver
//傳統手工 sql,一筆一筆加,時間約 32xxx ms
long time = System.currentTimeMillis();
Connection c = DBPool.getConnection();
Statement stmt = c.createStatement();
for(int i=0; i<3000; i++){
stmt.execute(
"INSERT INTO `game_session` (`id` , `game_id` , `create_time` , `progress` ,`size`)"+
" VALUES ('"+i+"', '1', '1', '1', '1');");
}
stmt.execute("delete from game_session");
System.out.println(time-System.currentTimeMillis());
//傳統手工 sql,但是全部組完才執行,時間約 4xxx ms
long time = System.currentTimeMillis();
Connection c = DBPool.getConnection();
Statement stmt = c.createStatement();
StringBuffer sb = new StringBuffer("INSERT INTO `game_session` (`id` , `game_id` , `create_time` , `progress` ,`size`) VALUES ");
for(int i=0; i<3000; i++){
sb.append("('"+i+"', '1', '1', '1', '1'), ");
}
sb.append("('end', '1', '1', '1', '1') ");
stmt.execute(sb.toString());
stmt.execute("delete from game_session");
System.out.println(time-System.currentTimeMillis());
//PrepareStatement,用法應該沒有錯 XD
//時間跟第一個傳統手工的,根本沒差別... Orz
long time = System.currentTimeMillis();
Connection c = DBPool.getConnection();
PreparedStatement pstmt = c.prepareStatement(
"INSERT INTO `game_session` (`id` ,`game_id` ,`create_time` ,`progress`, `size`) " +
"VALUES ( ?, ?, ?, ?, ?)");
for(int i=0; i<3000; i++){
pstmt.setString(1, ""+i);
pstmt.setString(2, ""+i);
pstmt.setLong(3, new Date().getTime());
pstmt.setString(4, ""+i);
pstmt.setString(5, ""+i);
pstmt.addBatch();
}
pstmt.executeBatch();
pstmt.execute("delete from game_session");
System.out.println(time-System.currentTimeMillis());
如果有謬誤之處,還請指正
--
侃侃長論鮮窒礙 首頁:http://www.psmonkey.idv.tw
眾目睽睽無心顫 Blog:http://ps-think.blogspot.com
煢居少聊常人事
殺頭容易告白難 歡迎參觀 Java 版(@ptt.cc)精華區 \囧/
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 58.114.193.216
推
09/04 20:49, , 1F
09/04 20:49, 1F
推
09/04 20:58, , 2F
09/04 20:58, 2F
推
09/04 23:07, , 3F
09/04 23:07, 3F
推
09/04 23:57, , 4F
09/04 23:57, 4F
→
09/04 23:58, , 5F
09/04 23:58, 5F
→
09/05 00:33, , 6F
09/05 00:33, 6F
→
09/05 00:38, , 7F
09/05 00:38, 7F