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

王朝学院·作者佚名  2010-05-27
窄屏简体版  字體: 小  |  中  |  大  |  超大  

对于海量数据的插入和更新,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

来更新,就我这个小数据量的测试而言,把10万条数据Fill到DataSet中已经不能工作,如果是百万,千万如何操作?难道一定先把要批操作的记录

先获取到DataSet中?也就是我要更新哪些记录就要选查询这些记录?

于是我仍然利用一个空的DataTable来加入要更新的记录:

sd.SelectCommand = new SqlCommand("select devid,data_time,data_value from CurrentTest where 1=0", conn);

//1=0的条件保证取一个空表.

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 i=0;i<300;i++){

..............................

dataset.Tables[0].Rows.Add(row);

}

sd.Update(dataset.Tables[0]);

先更新300条试试,如果成功再循环更新所有记录,但提示插入操作需要InsertCommand,因为一个空表然后Add Row操作,这时RowState是Added,

如果这时Update到数据库,执行的就是插入操作而无法更新. 改成:

for(int i=0;i<300;i++){

..............................

row = {填入初始化的值};

dataset.Tables[0].Rows.Add(row);

}

dataset.AcceptChanges();

for(int i=0;i<300;i++){

..............................

dataset.Tables[0].Rows[i][x] = "xxxxxxx";

..............................

}

sd.Update(dataset.Tables[0]);

先在DataTable中插入数据,然后用AcceptChanges(),修改RowState为UnChanged,再修改表中数据希望改变UnChanged状态,即将

DataTable从Current状态改为Original,然后再对DataTable的Row进行更新,就能使

Update成功.但这样做确实不方便.

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

sd.SelectCommand = new SqlCommand("select top 200 devid,data_time,data_value from CurrentTest", conn);

DataSet dataset = new DataSet();

sd.Fill(dataset);

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

for (int i = 0; i < 100; i++)

{

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"+(i+10000);//更新DEVID10000到DEVID10200的记录

dataset.Tables[0].Rows[i].EndEdit();

}

sd.Update(dataset.Tables[0]);

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

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

http://www.cnblogs.com/Seabiscuit/archive/2010/05/25/1743341.html

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航