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

C#中海量数据的批量插⼊和更新
对于海量数据的插⼊和更新,ADO.NET确实不如JDBC做到
好,JDBC有统⼀的模型来进⾏批操作.使⽤起来
⾮常⽅便:
PreparedStatement ps = conn.prepareStatement("insert or update ");
然后你就可以
for(int i=0;i<1000000000000000;i++){
ps.setXXX(realArg);
.....
ps.addBatch();
if(i%500==0){ //假设五百条提交⼀次
//clear Parame Batch
}
}
这样的操作不仅带来极度⼤的性能,⽽且⾮常⽅便.按说,ADO.NET 中,要实现这样的功能,应该直接在Command接⼝中
或DataAdapter接⼝中提供Addbat和CommitBat的API,但ADO.NET的却并没有这样简单地实现,⽽是要求开发者通过
复杂的变通⽅法.
对于⼤量的插⼊操作,可以利⽤⼀个空的DataTable加⼊要插⼊的⾏,达到⼀定数量提交后清空该表就⾏了,
实现起来并不算复杂:
DateTime begin = DateTime.Now;
string connectionString = ......;
using(SqlConnection conn = new SqlConnec
tion(connectionString)){
conn.Open();
SqlDataAdapter sd = new SqlDataAdapter(
);
sd.SelectCommand = new SqlCommand("
select devid,data_time,data_value from Curr
entTest", conn);
sd.InsertCommand = new SqlCommand("i
nsert into CurrentTest (devid,data_time,data
_value) "
+ " values (@devid,@data_time,
@data_value);", conn);
sd.InsertCommand.Parameters.Add("@de
vid", SqlDbType.Char, 18, "devid");
sd.InsertCommand.Parameters.Add("@dat
a_time", SqlDbType.Char, 19, "data_time");
sd.InsertCommand.Parameters.Add("@dat
a_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.TotalMilliseco
nds);
对于这个测试我插⼊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_va
lue = @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 Sql
Connection(connectionString)){
conn.Open();
SqlDataAdapter sd = new SqlDataA
dapter();
sd.SelectCommand = new SqlCom
mand("select top 200 devid,data_time,data_v
alue from CurrentTest", conn);
DataSet dataset = new DataSet();
sd.Fill(dataset);
Random r = new Random(1000);
sd.UpdateCommand = new SqlCom
mand("update CurrentTest "
+ " set data_time = @data
_time,data_value = @data_value where devid
= @devid", conn);
sd.UpdateCommand.Parameters.Ad
d("@data_time", SqlDbType.Char, 19, "data_
time");
sd.UpdateCommand.Parameters.Ad
d("@data_value", SqlDbType.Int, 4, "data_va
lue");
sd.UpdateCommand.Parameters.Ad
d("@devid", SqlDbType.Char, 20, "devid");
sd.UpdateCommand.UpdatedRowS
ource = UpdateRowSource.None;
sd.UpdateBatchSize = 0;
for (int count = 0; count < 100000;)
{
for (int i = 0; i < 200; i++,count++)
{
dataset.Tables[0].Rows[i].Begi
nEdit();
dataset.Tables[0].Rows[i]["dat
a_time"] = "2222-22-22 22:22:22";
dataset.Tables[0].Rows[i]["dat
a_value"] = 100;
dataset.Tables[0].Rows[i]["dev
id"] = "DEVID"+count;
dataset.Tables[0].Rows[i].End
Edit();
}
sd.Update(dataset.Tables[0]);
}
dataset.Tables[0].Clear();
sd.Dispose();
dataset.Dispose();
conn.Close();
}
TimeSpan ts = DateTime.Now - begin;
MessageBox.Show("ts = " + ts.TotalM illiseconds);
注意上⾯的更新操作是指在⼀个⼗万,百万,千万条记录中我要不断更新其中的记录,这些要更新的记录并不是从头
到尾这样的顺序,只是不断地根据条件更新任何记录,我不可能把成百上千万记录先Fill到ds中然后在ds中Select到
这条记录然后更新,所以每200次更新操作填⼊⼀次DataTable中提交,就实现了JDBC的addBat和executeBat操作.
这个操作更新10万条⽤了32秒,还算勉强吧.
KAO,没有更优雅的⽅法了.只好将就这样⽤了.

本文发布于:2024-09-20 17:44:31,感谢您对本站的认可!

本文链接:https://www.17tex.com/tex/2/90141.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:数据   记录   实现   提交   操作   思路   改变   希望
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议