批量导入真的可以提高效率吗,JDBC批量导入和普通循环插入数据的比较
一直没试过批量导入,今天看看效果,首选说明下我的环境,数据库SQL Server2000,tomcat,都是在同一台机进行,我做了导入10W条记录的比较:
两段代码如下:
1。普通循环插入的代码:
- Java code
out.println("循环插入数据...<br/>"); long startTime = System.currentTimeMillis(); Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver").newInstance(); String url = "jdbc:microsoft:sqlserver://127.0.0.1:1433;DatabaseName=yiqianmi"; //test你的数据库的 String user = "sa"; String password = "ok"; Connection conn = DriverManager.getConnection(url,user,password); conn.setAutoCommit(false); PreparedStatement pst = (PreparedStatement)conn.prepareStatement("insert into batch_index values (?,?,?,?)"); int addNum = 100000; int startPos = 0; int endPos = addNum+startPos; out.println("插入"+addNum+"条数据<br>"); java.util.Date curDate = new java.util.Date(); java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm"); String curDateStr = sdf.format(curDate); System.out.println("循环插入"+addNum+"条数据..."); for(int i=startPos+1; i<=endPos; i++){ pst.setInt(1,i); pst.setInt(2,i+100); pst.setString(3,new String(("第"+i+"班名称").getBytes("GBK"),"iso8859-1")); pst.setString(4, curDateStr); pst.execute(); } conn.commit(); System.out.println("================================================"); System.out.println("插入成功"); conn.close(); long endTime = System.currentTimeMillis(); out.println("消耗时间:"+(endTime-startTime)+"ms");2。批量导入代码:
- Java code
out.println("批量插入数据...<br/>"); long startTime = System.currentTimeMillis(); Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver").newInstance(); String url = "jdbc:microsoft:sqlserver://127.0.0.1:1433;SelectMethod=cursor;DatabaseName=yiqianmi"; //test你的数据库的 String user = "sa"; String password = "ok"; Connection conn = DriverManager.getConnection(url,user,password); conn.setAutoCommit(false); PreparedStatement pst = (PreparedStatement)conn.prepareStatement("insert into batch_index values (?,?,?,?)"); int addNum = 100000; int startPos = 0; int endPos = addNum+startPos; out.println("插入"+addNum+"条数据<br>"); java.util.Date curDate = new java.util.Date(); java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm"); String curDateStr = sdf.format(curDate); System.out.println("批量插入"+addNum+"条数据..."); for(int i=startPos+1; i<=endPos; i++) { pst.setInt(1,i); pst.setInt(2,i+100); pst.setString(3,new String(("第"+i+"班名称").getBytes("GBK"),"iso8859-1")); pst.setString(4,curDateStr); pst.addBatch(); if(i % 100 == 0){ pst.executeBatch(); } } pst.executeBatch(); conn.commit(); System.out.println("================================================"); System.out.println("插入成功"); conn.close(); long endTime = System.currentTimeMillis(); out.println("消耗时间:"+(endTime-startTime)+"ms");两个测试结果是:
循环插入数据...
插入100000条数据
消耗时间:14156ms
批量插入数据...
插入100000条数据
消耗时间:13734ms
在运行期间CPU咱占用率都很正常,请大家有时间看一下,两个结果的消耗时间都差不多,不知道批量导入到底效率高在哪?
------解决方案--------------------
我的解释:
1、对于insert语句,速度瓶颈主要是在磁盘IO上,所以,批量提交带来的优化效果有限。
2、(这只是猜测)因为是SQL Server,你的数据库空间分配了多大,如果数据库空间过小,Sql Server一般动态扩张数据文件,会占用较多的事件,
应交替多做几次测试(每次测试要清空数据库),看平均。
3、将start时间放到for循环之前,得到的结果会更精确一写。
4、将批次设置的更大一写,如:1000试试。
[解决办法]
补充一句:
如果是服务器,一般磁盘IO比较快,所以带来的性能提升会稍微明显一写,另外跟你数据库设置的缓存大小也有关系,因为这决定了数据库多久像磁盘提交一次更新。
[解决办法]
还有,把endTime放到commit之前,再对比一下看看有什么不同?
[解决办法]
你只是在sql server 上测试,建议你在不同数据库间进行测试,看看,这个程序相关,也跟驱动相关。
其实批量导入导出不建议在java程序中进行,至少我开发的项目中不建议。一般大批量的数据库操作尽量用存储过程或者直接调用工具执行。
[解决办法]
[解决办法]
这样的测试好。
我觉得从理论上讲两种方法确实应该差不多的。
[解决办法]
[解决办法]
[解决办法]
LZ有空试下这个(没调试过):
out.println("批量插入数据...<br/>");
long startTime = System.currentTimeMillis();
Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver").newInstance();
String url = "jdbc:microsoft:sqlserver://127.0.0.1:1433;SelectMethod=cursor;DatabaseName=yiqianmi";
//test你的数据库的
String user = "sa";
String password = "ok";
Connection conn = DriverManager.getConnection(url,user,password);
conn.setAutoCommit(false);
PreparedStatement pst = (PreparedStatement)conn.prepareStatement("insert into batch_index values (?,?,?,?)");
int addNum = 100000;
int startPos = 0;
int endPos = addNum+startPos;
int refPos = endPos/100;
out.println("插入"+addNum+"条数据<br>");
java.util.Date curDate = new java.util.Date();
java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm");
String curDateStr = sdf.format(curDate);
System.out.println("批量插入"+addNum+"条数据...");
for(int i=startPos+1; i<=refPos; i++) {
for(int j=0; j<100; j++){
pst.setInt(1,i+j);
pst.setInt(2,i+100);
pst.setString(3,new String(("第"+(i+j)+"班名称").getBytes("GBK"),"iso8859-1"));
pst.setString(4,curDateStr);
pst.addBatch();
}
pst.executeBatch();
}
pst.executeBatch();
conn.commit();
System.out.println("================================================");
System.out.println("插入成功");
conn.close();
long endTime = System.currentTimeMillis();
out.println("消耗时间:"+(endTime-startTime)+"ms");
------解决方案--------------------
差别还是很大的,我用oracle测试了下。
插了三个字段
循环插入用时 44500ms
批量插入用时 3407ms
[解决办法]
我觉得是你的数据量不大,和数据库在压力过小造成的,真正 的项目中,会有很大的差距!
[解决办法]
调用存触过程吧
[解决办法]
Java 深度探索者 QQ群:65670864