對於海量數據的插入和更新,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#中完成海量數據的批量插入和更新
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.