请牛人优化一下下面的代码,关于List海量数据的。

hui717 2008-05-08 01:13:54

/// <summary>
/// 检查是否有重复的码
/// </summary>
/// <param name="aadt">准备写入数据库的DataTable</param>
/// <param name="icodesum">码的总个数</param>
/// <param name="ilength">码的长度</param>
/// <param name="scode">码的关键字</param>
/// <returns>经过处理后,无重复码的List链表</returns>
private List<string> CheckWriteData(DataTable aadt,int icodesum,int ilength,string scode)
{
using (SqlConnection conn = new SqlConnection())
{
List<string> value = new List<string>(icodesum);
SqlCommand cmd = new SqlCommand();
conn.ConnectionString = ConfigurationManager.ConnectionStrings["fwwlConnectionString"].ConnectionString;
conn.Open();
try
{
//首先删除临时表的记录
cmd.CommandTimeout = 600;
cmd.Connection = conn;
cmd.CommandType = CommandType.Text;
cmd.CommandText = "Delete TmpCode";
cmd.ExecuteNonQuery();

//把所生的码写入临时表(可能会有复制的码)
using (SqlBulkCopy bcp = new SqlBulkCopy(conn))
{
bcp.BatchSize = aadt.Rows.Count % 100;
bcp.BulkCopyTimeout = 3600;
bcp.DestinationTableName = "TmpCode";
bcp.WriteToServer(aadt);
}

using (DataTable dt = new DataTable ())
{
//把重复的码去掉,并补齐个数
cmd.CommandTimeout = 3600;
cmd.CommandText = "Select DISTINCT code from TmpCode";
SqlDataAdapter sdr = new SqlDataAdapter (cmd);
sdr.Fill(dt);

//检查有多少个重复的码,并用循环补足个数
if (dt.Rows.Count < icodesum)
{
int i = icodesum - dt.Rows.Count;
for (int m = 0; m < i; m++)
{
DataRow dr = dt.NewRow();
dr["code"] = Code(ilength, scode, m).ToString(); //生成新的码
dt.Rows.Add(dr);
}
}

//把DataTable中的数据,存入List中,准备返回
for (int m = 0; m < dt.Rows.Count; m++)
{
value.Add(dt.Rows[m]["code"].ToString());
}
dt.Dispose();
}
return value;
}
catch (Exception ex)
{
FileLog.InsertXml(ex.Message);
return value;
}
}
}



如量数据量在100万,或150万的时候,速度还可以接受。但超过150万的时候,程序几乎无法运行了。

请牛人帮忙解决一下。

几天了,实在想不出更好的方法了。
在线等。
小弟先谢了
...全文
461 26 打赏 收藏 转发到动态 举报
写回复
用AI写文章
26 条回复
切换为时间正序
请发表友善的回复…
发表回复
lqs0112 2008-05-09
  • 打赏
  • 举报
回复
学习
caicai_45 2008-05-09
  • 打赏
  • 举报
回复

楼主如果决定在数据库上优化的话,建议到sql版。
效率应该能提高不少的。
针对sql的优化方法就很多了,到了百万级,表变量和临时表已经有区别了。临时表可以加索引,而表变量是不可以加的。
hui717 2008-05-09
  • 打赏
  • 举报
回复
如果用UPDATE来做的话,代码就要复杂一些了。
要取出重复的码,
caicai_45 2008-05-09
  • 打赏
  • 举报
回复
while @tableCount > 0 --补齐码的个数
这个地方的循环插入应该是比较耗时的,我感觉。 可以换个思路,先做整体插入,然后重复的部分采用update的机制来做,可能快一些
caicai_45 2008-05-09
  • 打赏
  • 举报
回复
如果数据库优化的话,建议加些索引,10分钟,应该能更快一些
hui717 2008-05-09
  • 打赏
  • 举报
回复
多谢各位,最终我觉定在数据库中用一个存储过程来解决这个问题。
当数量为200万条记录时,用时10分钟左右,但不会死机了。


CREATE PROCEDURE [dbo].[CheckDataDistinct]
@tableName nvarchar(30), --表名
@sumCount int, --码的个数
@ilength_fw int, --防伪码的长度
@ilength_wl int, --物流码的长度
@scode nvarchar(10) --码的关键字
AS
declare @strSql nvarchar(300) --存储准备执行的SQL语句
declare @tableCount int
declare @tmpCode_fw nvarchar(30) --临时存放新生成的码
declare @tmpCode_wl nvarchar(30) --临时存放新生成的码

--从大到小处理物流码
Create Table #MyTmpeTable(id int,code_fw nvarchar(30),code_wl nvarchar(30),
flag_wl int, select_Sum_Count int)
Set @strSql = '
Insert Into #MyTmpeTable
Select a.*
from '+ @tableName + ' a where
id = (select min(id) from '+@tableName+' where code_wl = a.code_wl) order by a.id'
exec(@strSql)--去掉物流码的所有重复值
Select @tableCount = Count(id) From #MyTmpeTable --去掉重复值后还剩于的码个数

while @tableCount < @sumCount --补齐码的个数
begin
Set @tmpCode_fw = dbo.Code(@ilength_fw,@scode,@tableCount) --生成新码
Set @tmpCode_wl = dbo.Code(@ilength_wl,@scode,@tableCount) --生成新码
Insert into #MyTmpeTable(id,code_fw,code_wl,flag_wl,select_Sum_Count)
Values(@tableCount,@tmpCode_fw,@tmpCode_wl,0,0)
Set @tableCount = @tableCount+1
end

--从小到大处理防伪码
Create Table #MyTable_fw(id int,code_fw nvarchar(30),code_wl nvarchar(30),
flag_wl int, select_Sum_Count int)
Set @strSql = '
Insert Into #MyTable_fw
Select a.*
from #MyTmpeTable a where
id = (select min(id) from #MyTmpeTable where code_fw = a.code_fw) order by a.id'
exec(@strSql)--去掉防伪码的所有重复值
Select @tableCount = Count(id) From #MyTable_fw --去掉重复值后还剩于的码个数
Set @tableCount = @sumCount - @tableCount
while @tableCount > 0 --补齐码的个数
begin
Set @tmpCode_fw = dbo.Code(@ilength_fw,@scode,@tableCount) --生成新码
Set @tmpCode_wl = dbo.Code(@ilength_wl,@scode,@tableCount) --生成新码
Insert into #MyTable_fw(id,code_fw,code_wl,flag_wl,select_Sum_Count)
Values(@tableCount,@tmpCode_fw,@tmpCode_wl,0,0)
Set @tableCount = @tableCount - 1
end

--把处理后的码,写回原表中

Set @strSql = 'delete '+@tableName
exec(@strSql)

Set @strSql = 'Insert into '+@tableName+' (code_fw,code_wl,flag_wl,select_Sum_Count '+
') Select code_fw,code_wl,flag_wl,select_Sum_Count From #MyTable_fw '
exec(@strSql)
GO






CREATE FUNCTION [dbo].[Code] (@ilength int,@scode nvarchar(30),@inum int)
RETURNS nvarchar(50)
BEGIN
--变量
declare @alength int
declare @strTmp nvarchar(50) --新生成的码,返回用

set @alength = @ilength - 6 --需要补齐的位数
Set @strTmp = @inum --码的关键字

if len(@strTmp) > @alength
begin
Set @strTmp = substring(@strTmp,1,@ilength)
end
else
begin
declare @ailength int
set @ailength = @alength - len(@strTmp) --需要循环处理的次数
declare @j int
set @j = 0

while @j < @ailength
begin
Set @strTmp = '0'+@strTmp
Set @j = @j+1
end
Set @strTmp = @scode + @strTmp
end

RETURN(@strTmp)
END

hui717 2008-05-09
  • 打赏
  • 举报
回复
多谢各位,问题已经基本解决了。
生成600万个随机、不重复的码,20分钟左右就可以了。

lake_cx 2008-05-08
  • 打赏
  • 举报
回复
我就不相信你哪个地方要一次用到这List中所有的数据
当数据量大时,原则是要用哪些就取哪些

你先说说你返回那么大一个List打算干嘛吧
noky 2008-05-08
  • 打赏
  • 举报
回复
在数据库原理里面专门有一章是介绍范式的,有第一级范式,第二级范式,第三级范式(好像叫范式)其目的是最小化数据表(跟面向对象中的最小耦合度类似),如果你的表中有这么多重复的值,而且还需要大量的操作。那你就可以考虑将你的数据表在细分出来,分成两个、三个或者更多的子表,通过主键和外键进行联系。操作。
像你这样所有的数据都在数据库之外自己处理,那还要数据库干什么呢?我觉得你的思路有问题,照你的思路下去,你这个项目必定失败
Scarroot 2008-05-08
  • 打赏
  • 举报
回复
学习一下
r_swordsman 2008-05-08
  • 打赏
  • 举报
回复
你的字符串都是从数据库里面读出来的,干嘛不直接在数据库里面处理?
hui717 2008-05-08
  • 打赏
  • 举报
回复
那按 孤狼傲血 的意思,难道上百万的一个字符串数组中,要去掉年重复值,难道就没有办法了???
hui717 2008-05-08
  • 打赏
  • 举报
回复
多谢,我改一下试试,再来请教
noky 2008-05-08
  • 打赏
  • 举报
回复
奉劝你一句,别在这里浪费时间了,如果你取出来的数据非常的大,而且非常多的重复,那么就建议你取重构你的数据表,在C#中,List存储、时延、响应等等的效率是最高的,除非你比微软牛B,自己些一个List,否则就别在这里找出路了,其实是找到也不会高效到那里去,本末倒置了。
cancerser 2008-05-08
  • 打赏
  • 举报
回复
还有就是这里用 sqlreader 效率要高很多(cmd.ExecuteReader();……)
最后 能不写ToString的 就别写,那可是内存啊
cancerser 2008-05-08
  • 打赏
  • 举报
回复
中间有几个变量没改过来,自己改改 ,写的只是个意思.
提升速度的原则是 ,能用简单的不用复杂的 ,能用值类型,不用引用类型
badtank 2008-05-08
  • 打赏
  • 举报
回复
小改了一下,感觉没必要把重复的码先放进datatable中,直接往list中放就可以了
另外,用hashtable来替换list是不是更好些。

private List<string> CheckWriteData(DataTable aadt, int icodesum, int ilength, string scode)
{
using (SqlConnection conn = new SqlConnection())
{
List<string> value = new List<string>();
SqlCommand cmd = new SqlCommand();
conn.ConnectionString = ConfigurationManager.ConnectionStrings["fwwlConnectionString"].ConnectionString;
conn.Open();
try
{
//首先删除临时表的记录
cmd.CommandTimeout = 600;
cmd.Connection = conn;
cmd.CommandType = CommandType.Text;
cmd.CommandText = "Delete TmpCode";
cmd.ExecuteNonQuery();

//把所生的码写入临时表(可能会有复制的码)
using (SqlBulkCopy bcp = new SqlBulkCopy(conn))
{
bcp.BatchSize = aadt.Rows.Count % 100;
bcp.BulkCopyTimeout = 3600;
bcp.DestinationTableName = "TmpCode";
bcp.WriteToServer(aadt);
}

using (DataTable dt = new DataTable())
{
//把重复的码去掉,并补齐个数
cmd.CommandTimeout = 3600;
cmd.CommandText = "Select DISTINCT code from TmpCode";
SqlDataAdapter sdr = new SqlDataAdapter(cmd);
sdr.Fill(dt);

//把DataTable中的数据,存入List中,准备返回
for (int m = 0; m < dt.Rows.Count; m++)
{
value.Add(dt.Rows[m]["code"].ToString());

}
if (dt.Rows.Count < icodesum) {
string newcode = Code(ilength, scode, m).ToString();
for (int i = dt.Rows.Count - 1; i < icodesum; i++)
{
value.Add(newcode);
}
}
dt.Dispose();
}
return value;
}
catch (Exception ex)
{
FileLog.InsertXml(ex.Message);
return value;
}
}
}
cancerser 2008-05-08
  • 打赏
  • 举报
回复


//using (DataTable dt = new DataTable())
//{
//把重复的码去掉,并补齐个数
cmd.CommandTimeout = 3600;
cmd.CommandText = "Select DISTINCT code from TmpCode";
//SqlDataAdapter sdr = new SqlDataAdapter(cmd);
//sdr.Fill(dt);
SqlDataReader dr = cmd.EndExecuteReader();
while (dr.Read())
{
value.Add(dr["code"].ToString());
}
dr.Close();
//检查有多少个重复的码,并用循环补足个数
if (dt.Rows.Count < icodesum)
{
int i = icodesum - dt.Rows.Count;
for (int m = 0; m < i; m++)
{
//DataRow dr = dt.NewRow();
//dr["code"] = Code(ilength, scode, m).ToString(); //生成新的码
//dt.Rows.Add(dr);
value.Add(Code(ilength, scode, m).ToString());
}
}

//把DataTable中的数据,存入List中,准备返回
//for (int m = 0; m < dt.Rows.Count; m++)
//{
// value.Add(dt.Rows[m]["code"].ToString());
//}
//dt.Dispose();
//}

// 其实去掉重复值的办法有很多,比如用hashTable,只一个字段的类型 怎么写都没所谓了
hui717 2008-05-08
  • 打赏
  • 举报
回复
我也试过,把DataTable中的内容搞进DataView中,然后再利用DataView的ToTable()方法来去掉重复值,这样就可以不用读写数据库了。
不过这种方法好像更慢样。
hui717 2008-05-08
  • 打赏
  • 举报
回复
用list 返回时,150万的数据,也就六七分钟左右时间,还可以接受。
大过150万的时候,程序就死了。

code 是一个字符串型,

dr["code"] = Code(ilength, scode, m).ToString(); //生成新的码

这个地方当参数传递使用
加载更多回复(6)

110,534

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧