热门:网页模板.net视频教程JQueryMVCjsonExtJs源码示例三级联动JQuery菜单
您现在的位置:.Net中文社区>> .Net编程>>正文内容

C#中海量数据的批量插入和更新

发布时间:2010年05月25日点击数: 佚名

对于海量数据的插入和更新,ADO.NET确实不如JDBC做到好,JDBC有统一的模型来进行批操作.使用起来非常方便:

  1. PreparedStatement ps = conn.prepareStatement("insert or update arg1,args2...."); 

然后你就可以

  1. for(int i=0;i<1000000000000000;i++){ 
  2.   ps.setXXX(realArg); 
  3.   ..... 
  4.   ps.addBatch(); 
  5.   if(i%500==0){ //假设五百条提交一次 
  6.    ps.executeBatch(); 
  7.    //clear Parame Batch 
  8.   } 
  9.  } 
  10.  ps.executeBatch(); 

这样的操作不仅带来极度大的性能,而且非常方便.按说,ADO.NET中,要实现这样的功能,应该直接在Command接口中
或DataAdapter接口中提供Addbat和CommitBat的API,但ADO.NET的却并没有这样简单地实现,而是要求开发者通过复杂的变通方法.
 对于大量的插入操作,可以利用一个空的DataTable加入要插入的行,达到一定数量提交后清空该表就行了,
实现起来并不算复杂:

  1. DateTime begin = DateTime.Now; 
  2. string connectionString = ......; 
  3. using(SqlConnection conn = new SqlConnection(connectionString)){ 
  4.     conn.Open(); 
  5.     SqlDataAdapter sd = new SqlDataAdapter(); 
  6.     sd.SelectCommand = new SqlCommand("select devid,data_time,data_value from CurrentTest", conn); 
  7.     sd.InsertCommand = new SqlCommand("insert into CurrentTest (devid,data_time,data_value) " 
  8.                     + " values (@devid,@data_time,@data_value);", conn); 
  9.     sd.InsertCommand.Parameters.Add("@devid", SqlDbType.Char, 18, "devid"); 
  10.     sd.InsertCommand.Parameters.Add("@data_time", SqlDbType.Char, 19, "data_time"); 
  11.     sd.InsertCommand.Parameters.Add("@data_value", SqlDbType.Int, 8, "data_value"); 
  12.     sd.InsertCommand.UpdatedRowSource = UpdateRowSource.None; 
  13.     sd.UpdateBatchSize = 0; 
  14.  
  15.     DataSet dataset = new DataSet(); 
  16.     sd.Fill(dataset); 
  17.     Random r = new Random(1000); 
  18.     for (int i = 0; i < 100000; i++) { 
  19.         object[] row = {"DEVID"+i,DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),r.Next(1,1000) }; 
  20.         dataset.Tables[0].Rows.Add(row); 
  21.         if (i % 300 == 0) { 
  22.             sd.Update(dataset.Tables[0]); 
  23.             dataset.Tables[0].Clear(); 
  24.         } 
  25.     } 
  26.     sd.Update(dataset.Tables[0]); 
  27.     dataset.Tables[0].Clear(); 
  28.     sd.Dispose(); 
  29.     dataset.Dispose(); 
  30.     conn.Close(); 
  31.     
  32. TimeSpan ts = DateTime.Now - begin; 
  33. MessageBox.Show("ts = " + ts.TotalMilliseconds); 

对于这个测试我插入10万条数据用时28秒.性能还算可圈可点.但是对于批量更新,搜遍全球的例子,都是把记录Fill到DataSet中然后牧举rows来更新,就我这个小数据量的测试而言,把10万条数据Fill到DataSet中已经不能工作,如果是百万,千万如何操作?难道一定先把要批操作的记录
先获取到DataSet中?也就是我要更新哪些记录就要选查询这些记录?
 于是我仍然利用一个空的DataTable来加入要更新的记录:

  1. sd.SelectCommand = new SqlCommand("select devid,data_time,data_value from CurrentTest where 1=0", conn); 
  2.  //1=0的条件保证取一个空表. 
  3.  sd.UpdateCommand = new SqlCommand("update CurrentTest set data_time = @data_time,data_value = @data_value where devid = @devid", conn); 
  4.         sd.UpdateCommand.Parameters.Add("@data_time", SqlDbType.Char, 19, "data_time"); 
  5.         sd.UpdateCommand.Parameters.Add("@data_value", SqlDbType.Int, 4, "data_value"); 
  6.         sd.UpdateCommand.Parameters.Add("@devid", SqlDbType.Char, 20, "devid"); 
  7.         sd.UpdateCommand.UpdatedRowSource = UpdateRowSource.None; 
  8.         sd.UpdateBatchSize = 0; 
  9.  for(int i=0;i<300;i++){ 
  10.   .............................. 
  11.   dataset.Tables[0].Rows.Add(row); 
  12.  } 
  13.  sd.Update(dataset.Tables[0]); 

先更新300条试试,如果成功再循环更新所有记录,但提示插入操作需要InsertCommand,因为一个空表然后Add Row操作,这时RowState是Added,
如果这时Update到数据库,执行的就是插入操作而无法更新. 改成:

  1. for(int i=0;i<300;i++){ 
  2.   .............................. 
  3.  row = {填入初始化的值}; 
  4.   dataset.Tables[0].Rows.Add(row); 
  5.  } 
  6.  dataset.AcceptChanges(); 
  7.  for(int i=0;i<300;i++){ 
  8.   .............................. 
  9.   dataset.Tables[0].Rows[i][x] = "xxxxxxx"
  10.   .............................. 
  11.  } 
  12.  sd.Update(dataset.Tables[0]); 

先在DataTable中插入数据,然后用AcceptChanges(),修改RowState为UnChanged,再修改表中数据希望改变UnChanged状态,即将
DataTable从Current状态改为Original,然后再对DataTable的Row进行更新,就能使Update成功.但这样做确实不方便.

 调整思路,先从数据库中取200条(批更新的Size大小),直接得到一个Original的DataTable.

  1. sd.SelectCommand = new SqlCommand("select top 200 devid,data_time,data_value from CurrentTest", conn); 
  2.  DataSet dataset = new DataSet(); 
  3.         sd.Fill(dataset); 

用这200个空间来放要更新的其它数据看看:

  1. for (int i = 0; i < 100; i++) 
  2.                     { 
  3.                         dataset.Tables[0].Rows[i].BeginEdit(); 
  4.                         dataset.Tables[0].Rows[i]["data_time"] = "2222-22-22 22:22:22"
  5.                         dataset.Tables[0].Rows[i]["data_value"] = 100; 
  6.                         dataset.Tables[0].Rows[i]["devid"] = "DEVID"+(i+10000);//更新DEVID10000到DEVID10200的记录 
  7.                         dataset.Tables[0].Rows[i].EndEdit(); 
  8.                     } 
  9.                     sd.Update(dataset.Tables[0]); 

OK,成功,哈哈.把要更新的数据不断往这个空间填,填满就提交,这样更新100000条数据只要几个循环就行了.

  1. DateTime begin = DateTime.Now; 
  2.             string connectionString = ""
  3.             using(SqlConnection conn = new SqlConnection(connectionString)){ 
  4.                 conn.Open(); 
  5.  
  6.                 SqlDataAdapter sd = new SqlDataAdapter(); 
  7.                 sd.SelectCommand = new SqlCommand("select top 200 devid,data_time,data_value from CurrentTest", conn); 
  8.  
  9.                 DataSet dataset = new DataSet(); 
  10.                 sd.Fill(dataset); 
  11.                 Random r = new Random(1000); 
  12.  
  13.                 sd.UpdateCommand = new SqlCommand("update CurrentTest " 
  14.                                 + " set data_time = @data_time,data_value = @data_value where devid = @devid", conn); 
  15.                 sd.UpdateCommand.Parameters.Add("@data_time", SqlDbType.Char, 19, "data_time"); 
  16.                 sd.UpdateCommand.Parameters.Add("@data_value", SqlDbType.Int, 4, "data_value"); 
  17.                 sd.UpdateCommand.Parameters.Add("@devid", SqlDbType.Char, 20, "devid"); 
  18.                 sd.UpdateCommand.UpdatedRowSource = UpdateRowSource.None; 
  19.                 sd.UpdateBatchSize = 0; 
  20.                 for (int count = 0; count < 100000;) 
  21.                 { 
  22.  
  23.                     for (int i = 0; i < 200; i++,count++) 
  24.                     { 
  25.                         dataset.Tables[0].Rows[i].BeginEdit(); 
  26.                         dataset.Tables[0].Rows[i]["data_time"] = "2222-22-22 22:22:22"
  27.                         dataset.Tables[0].Rows[i]["data_value"] = 100; 
  28.                         dataset.Tables[0].Rows[i]["devid"] = "DEVID"+count; 
  29.                         dataset.Tables[0].Rows[i].EndEdit(); 
  30.                     } 
  31.                     sd.Update(dataset.Tables[0]); 
  32.                 } 
  33.    
  34.  
  35.                 dataset.Tables[0].Clear(); 
  36.                 sd.Dispose(); 
  37.                 dataset.Dispose 

本站热点业务

更多模板/案例展示

关于我们 | 联系我们 | 团队日志 | 网站地图 | 网站合作