一直没试过批量导入,今天看看效果,首选说明下我的环境,数据库SQL Server2000,tomcat,都是在同一台机进行,我做了导入10W条记录的比较:两段代码如下:
1。普通循环插入的代码:
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。批量导入代码:
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。普通循环插入的代码:
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。批量导入代码:
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咱占用率都很正常,请大家有时间看一下,两个结果的消耗时间都差不多,不知道批量导入到底效率高在哪?
2、(这只是猜测)因为是SQL Server,你的数据库空间分配了多大,如果数据库空间过小,Sql Server一般动态扩张数据文件,会占用较多的事件,
应交替多做几次测试(每次测试要清空数据库),看平均。
3、将start时间放到for循环之前,得到的结果会更精确一写。
4、将批次设置的更大一写,如:1000试试。
谢谢楼上两位
我不熟数据库空间分配和设置缓存
试过了jinxfei说过的方法,都是一样的结果。。另外在MySQL上也测试了下,结果是一样的批量插入数据MySQL...
插入100000条数据
消耗时间:18172ms 批量插入数据MySQL...
插入100000条数据
消耗时间:17390ms
对于在java中批量操作,需要考虑到的是java的对象回收和内存溢出问题。对于数据库批量插入的效率,这些与数据库的优化器,驱动包,表结构,与索引的设计有关系。
10万条记录还是太少,你可以尝试着100万,就让他在那里跑。吃个饭回来再看看效率。
建立逐步建立索引再测试再跑对于你说的数据库的空间分配与缓存不太明白你想问什么。对于一条语句执行后效率是否高,还要看你的sql是否满足数据库优化器的条件。关系数据库中是否打破了关系。都有关系。
不考虑索引问题的
再说下我的操作步骤:
1。首先新建一个表batch_index(classId int, personNum int, className varchar, createTime),表中没有任何数据
2。执行普通循环插入的JSP
3。清除原来的数据
4。执行批量插入的JSP
5。将两个结果进行比较就这样,很简单的操作
对上面的疑问:
如何进行数据库控件分配和设置缓存呢?
还要你说的对象回收,要怎么做才尽可能性能更好点?
刚刚执行完了100W数据的插入,结果如下:循环插入数据...
插入1000000条数据
消耗时间:138640ms
批量插入数据...
插入1000000条数据
消耗时间:143640ms 结果,批量还比循环多点了?倒...
不知道你的测试环境是怎么样的,第一个测试结束得到运行时间后 重新启动服务器,然后测试第二个。如果你中间没有重新启动的话测试结果不会准,因为先后顺序后有对象回收和内存争用问题。导致二个方法测试与第一测试环境不一致,从而出现误差。至于防止内存溢出如何解决,这就要看编辑的经验和技巧,还有对GC的理解。两个方法测试你最后的结果都是运行成功,其实还不是最终的结果,你应该不断的加大数量例如200万,500万,知道测试有一个方法退出舞台而另一个方法还健在的结果,然后再观察gc的情况,在这个器件gc执行了多次回收,利用了多少时间去回收,最后老年期内存占用多少,各是多少。这么数据都列出来。这样的测试才算一段落而已。
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");
插了三个字段
循环插入用时 44500ms批量插入用时 3407ms
感觉是数据库的问题耶,我在本机的sqlserver和mysql上建索引也不起效果..