对于海量数据的插入和更新,ADO.NET确实不如JDBC做到好,JDBC有统一的模型来进行批操作.使用起来
非常方便: PreparedStatement ps = conn.prepareStatement("insert or update arg1,args2...."); 然后你就可以 for(int i=0;i<1000000000000000;i++){ ps.setXXX(realArg); ..... ps.addBatch(); if(i%500==0){ //假设五百条提交一次 ps.executeBatch(); //clear Parame Batch } } ps.executeBatch(); 这样的操作不仅带来极度大的性能,而且非常方便.按说,ADO.NET中,要实现这样的功能,应该直接在Command接口中 或DataAdapter接口中提供Addbat和CommitBat的API,但ADO.NET的却并没有这样简单地实现,而是要求开发者通过 复杂的变通方法. 对于大量的插入操作,可以利用一个空的DataTable加入要插入的行,达到一定数量提交后清空该表就行了, 实现起来并不算复杂:
DateTime begin
=
DateTime.Now;
string connectionString = ......; using (SqlConnection conn = new SqlConnection(connectionString))...{ conn.Open(); SqlDataAdapter sd = new SqlDataAdapter(); sd.SelectCommand = new SqlCommand( " select devid,data_time,data_value from CurrentTest " , conn); sd.InsertCommand = new SqlCommand( " insert into CurrentTest (devid,data_time,data_value) " + " values (@devid,@data_time,@data_value); " , conn); sd.InsertCommand.Parameters.Add( " @devid " , SqlDbType.Char, 18 , " devid " ); sd.InsertCommand.Parameters.Add( " @data_time " , SqlDbType.Char, 19 , " data_time " ); sd.InsertCommand.Parameters.Add( " @data_value " , SqlDbType.Int, 8 , " data_value " ); sd.InsertCommand.UpdatedRowSource = UpdateRowSource.None; sd.UpdateBatchSize = 0 ; DataSet dataset = new DataSet(); sd.Fill(dataset); Random r = new Random( 1000 ); for ( int i = 0 ; i < 100000 ; i ++ ) ...{ object [] row = ...{ " DEVID " + i,DateTime.Now.ToString( " yyyy-MM-dd HH:mm:ss " ),r.Next( 1 , 1000 ) }; dataset.Tables[ 0 ].Rows.Add(row); if (i % 300 == 0 ) ...{ sd.Update(dataset.Tables[ 0 ]); dataset.Tables[ 0 ].Clear(); } } sd.Update(dataset.Tables[ 0 ]); dataset.Tables[ 0 ].Clear(); sd.Dispose(); dataset.Dispose(); conn.Close(); } TimeSpan ts = DateTime.Now - begin; MessageBox.Show( " ts = " + ts.TotalMilliseconds); 对于这个测试我插入10万条数据用时28秒.性能还算可圈可点.但是对于批量更新,搜遍全球的例子,都是把记录Fill到DataSet中然后牧举rows 于是我仍然利用一个空的DataTable来加入要更新的记录: sd.SelectCommand = new SqlCommand("select devid,data_time,data_value from CurrentTest where 1=0", conn); for(int i=0;i<300;i++){ 如果这时Update到数据库,执行的就是插入操作而无法更新. 改成: row = {填入初始化的值}; DataTable从Current状态改为Original,然后再对DataTable的Row进行更新,就能使 Update成功.但这样做确实不方便.
DateTime begin
=
DateTime.Now;
string connectionString = "" ; using (SqlConnection conn = new SqlConnection(connectionString))... { conn.Open(); SqlDataAdapter sd = new SqlDataAdapter(); sd.SelectCommand = new SqlCommand("select top 200 devid,data_time,data_value from CurrentTest", conn); DataSet dataset = new DataSet(); sd.Fill(dataset); Random r = new Random(1000); sd.UpdateCommand = new SqlCommand("update CurrentTest " + " set data_time = @data_time,data_value = @data_value where devid = @devid", conn); sd.UpdateCommand.Parameters.Add("@data_time", SqlDbType.Char, 19, "data_time"); sd.UpdateCommand.Parameters.Add("@data_value", SqlDbType.Int, 4, "data_value"); sd.UpdateCommand.Parameters.Add("@devid", SqlDbType.Char, 20, "devid"); sd.UpdateCommand.UpdatedRowSource = UpdateRowSource.None; sd.UpdateBatchSize = 0; for (int count = 0; count < 100000;) ...{ for (int i = 0; i < 200; i++,count++) ...{ dataset.Tables[0].Rows[i].BeginEdit(); dataset.Tables[0].Rows[i]["data_time"] = "2222-22-22 22:22:22"; dataset.Tables[0].Rows[i]["data_value"] = 100; dataset.Tables[0].Rows[i]["devid"] = "DEVID"+count; dataset.Tables[0].Rows[i].EndEdit(); } sd.Update(dataset.Tables[0]); } dataset.Tables[0].Clear(); sd.Dispose(); dataset.Dispose(); conn.Close(); } TimeSpan ts = DateTime.Now - begin; MessageBox.Show( " ts = " + ts.TotalMilliseconds);
到尾这样的顺序,只是不断地根据条件更新任何记录,我不可能把成百上千万记录先Fill到ds中然后在ds中Select到 这条记录然后更新,所以每200次更新操作填入一次DataTable中提交,就实现了JDBC的addBat和executeBat操作. 这个操作更新10万条用了32秒,还算勉强吧. KAO,没有更优雅的方法了.只好将就这样用了. |
在C#中完成海量数据的批量插入和更新
最新推荐文章于 2024-04-28 17:27:20 发布