读书人

批量导入真的可以提高效率吗JDBC批量

发布时间: 2012-01-31 21:28:41 作者: rapoo

批量导入真的可以提高效率吗,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程序中进行,至少我开发的项目中不建议。一般大批量的数据库操作尽量用存储过程或者直接调用工具执行。


[解决办法]

探讨

谢谢楼上两位
我不熟数据库空间分配和设置缓存
试过了jinxfei说过的方法,都是一样的结果。。

另外在MySQL上也测试了下,结果是一样的

批量插入数据MySQL...
插入100000条数据
消耗时间:18172ms

批量插入数据MySQL...
插入100000条数据
消耗时间:17390ms


[解决办法]
这样的测试好。

我觉得从理论上讲两种方法确实应该差不多的。

[解决办法]
探讨

刚刚执行完了100W数据的插入,结果如下:

循环插入数据...
插入1000000条数据
消耗时间:138640ms


批量插入数据...
插入1000000条数据
消耗时间:143640ms

结果,批量还比循环多点了?倒...

[解决办法]
探讨
引用:
这样的测试好。

我觉得从理论上讲两种方法确实应该差不多的。



为什么?

[解决办法]
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

读书人网 >J2EE开发

热点推荐