从另一个数据表更新数据表中数据的高效方法

4

我在ASP.NET Web Service项目中有一个数据表,这个数据表有大约500K条记录,包含39列,并且存在缓存中。 一分钟后,一个后台线程会访问数据库并从中获取更新的记录,我想将这些记录更新到缓存的数据表中,我使用以下方法,但是它需要相当长的时间才能完成:

foreach (DataRow dRNew in dtNew.Rows)
{
     DataRow row = dtOriginal.Select("ID=" + dRNew["ID"]).First();
     row["Column1"] = dRNew["Column1"];
     row["Column2"] = dRNew["Column2"];
     row["Column3"] = dRNew["Column3"];
}

我已经替换了以下行:

DataRow row = dtOriginal.Select("ID=" + dRNew["ID"]).First();

使用

DataRow row = dtOriginal.AsEnumerable().Where(r => ((Int64)r["ID"]).Equals(dRNew["ID"])).First();

但是徒劳无功,在我的笔记本上需要大约5分钟。

请问有人可以指导我到底哪里做错了吗?使用哪种方法可以更高效地完成,我不确定是否可以使用Dataset.Merge或其他方法。


4
“SCNR......数据表格......里面有39列和500K条记录,并且存在于缓存中”,这让我立刻大笑起来...数据表格+缓存+foreach+多线程+......太牛了!你一定是张无忌...” - user57508
2
其实我笑了,因为你追踪的环境真的很痛苦...在这种情况下,没有一个高效/可行的解决方案。我宁愿从一个基本问题开始:为什么你必须把值存储在某个地方?你在做什么?给我们一个更大的画面!... - user57508
你误解了“_hurt_”:就像看一个对DST、UTC等几乎没有任何了解的人,实现了一个非常聪明的系统。有人应该立即跳出来说“不行”——这就是我试图通过我的问题所达到的目的(你还没有回答)。我现在不能(也不想)给出任何建议——首先我需要答案!(一个正确的选项可能是:为什么不使用静态的Dictionary<TKey, TValue>,其中TValue可以是您的PK类型,而TValue则是其他38列)。顺便说一句:如果你认为增加RAM会有帮助,那就去做吧! - user57508
谢谢您给我带来这个新知识,我会仔细阅读这篇博客。是的,您说得对,每分钟我们都在获取新的或更新的行。 - Imran Balouch
最好集中你的数据访问:读取和写入都应该通过一个仓库完成,这样轮询就变得过时了。完成这个之后,你就可以使用疯狂的Linq查询了... :) - user57508
显示剩余4条评论
3个回答

1
尝试使用这个方法:DataRowCollection.Find。假设您的DataTable设置正确,它将是O(log(n)),而不是当前的O(N)。
foreach (DataRow dRNew in dtNew.Rows) 
{
     DataRow row = null;
     try
     {
         row = dtOriginal.Find(dRNew["ID"]);
     }
     catch (MissingPrimaryKeyException)
     {
         row = dtOriginal.Select("ID=" + dRNew["ID"]).First();
     }
     if (row != null)
     {
         row["Column1"] = dRNew["Column1"]; 
         row["Column2"] = dRNew["Column2"]; 
         row["Column3"] = dRNew["Column3"]; 
     }
} 

请不要忘记外部的 foreach。也许在数据集中使用连接更好? - user57508
这基本上就是 Merge 所做的。 - M Afifi
是的和不是...应该只更新3个39列,因此本质上不是一个真正的合并。 - user57508

1

我本以为使用这个会更快:

TableToUpdate.AsEnumerable().Join
(
    TableToUpdateFrom.AsEnumerable(),
    lMaster => lMaster["COMMON_FIELD"], lChild => lChild["COMMON_FIELD"],
    (lMaster, lChild) => new { lMaster, lChild }
    ).ToList().ForEach
(
o =>
{
    o.lMaster.SetField("FIELD_TO_BE_UPDATED1", o.lChild["FIELD_TO_BE_UPDATED_FROM1"].ToString());
    o.lMaster.SetField("FIELD_TO_BE_UPDATED2", o.lChild["FIELD_TO_BE_UPDATED_FROM2"].ToString());
    o.lMaster.SetField("FIELD_TO_BE_UPDATED3", o.lChild["FIELD_TO_BE_UPDATED_FROM3"].ToString());
    o.lMaster.SetField("FIELD_TO_BE_UPDATED_ETC", o.lChild["APPROVAL_SCORE_FROM_ETC"].ToString());
}
);

你好Naelem,能告诉我如何在这个LINQ中加入两个条件吗?就是在以上代码中如何添加另一个公共字段呢? - JOJO

1

你可以尝试这种方式

dtOriginal.Merge(dtNew);

为什么要复制而不是只使用dtOriginal.Merge(dtNew)? - M Afifi
@MAfifi 抱歉,我只是举了一个快速示例,你可以使用已经可用的这些方法来实现它,请按照适合你的代码顺序使用。 - HatSoft
非常感谢您的回答,我遇到的唯一问题是Merge语句在表中添加了新行,但我发现如果在我的数据表中放置一个主键,它将解决这个问题。 - Imran Balouch
如果其中一个表没有主键,你能执行 .Merge 操作吗? - East of Nowhere
在合并之前,您需要指定表的主键以实现所需的结果。 - Cogent

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接