作者PsMonkey (痞子军团团长)
看板java
标题Re: [问题] 如何快速插入大量资料到MySQL
时间Fri Sep 4 16:04:59 2009
※ 引述《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
1F:推 Earvin:PrepareStatement用addBatch然後executeBatch没比分开好? 09/04 20:49
2F:推 Earvin:addBatch那段多new Date().getTime(),内容会比传统的方式多 09/04 20:58
3F:推 asklove:多谢板主,采用全部组完再执行,已降低到七分钟左右 09/04 23:07
4F:推 asklove:估算了一下速度差不多是1秒1000笔 插入约花6.4秒 09/04 23:57
5F:→ asklove: 分钟 09/04 23:58
6F:→ adrianshum:不要embed value, 用 bind param 的做法,应该会快很多 09/05 00:33
7F:→ adrianshum:不过 batch update, prepare stmt etc 都要视乎DBMS 09/05 00:38