读取500万条记录,最后更新一列

时间:2011-08-23 21:18:43

标签: c# c#-4.0 ado.net

我必须在数据库中为表T1更新 500万条记录。这是一个C# tool READ (Select)表T1中的一列,比如说T1.col1,然后根据该列的逻辑提取一个值,最后得UPDATE具有此处理值的同一表中的另一列T1.col2并更新Db。

想要了解在C#/ ADO.NET中实现这一目标的最佳/优化方法吗?

  

注意:提取逻辑不能是SQL的一部分。那个逻辑是   嵌入在COM DLL中,我从.NET进行干预并申请   列Col1的值,用于生成一个新值,该值必须最终保存在T1.Col2中。

7 个答案:

答案 0 :(得分:1)

由于您需要通过COM对象传输某些操作的数据,这就是我要做的事情:

使用具有大量内存的计算机 - 将数据以块(例如,每次5000或50000行)加载到内存中,处理它并在SQL Server上执行更新...

对于UPDATE部分,使用交易并将5000 - 20000更新放入一个交易...

[编辑] :通过正确分区工作并将500000或1000000行分配给一个“工作机器”,您可以将其加速到SQL Server的最大限制... <强> [/ EDIT]

另一种选择 - 虽然不推荐(仅因为在这种特定情况下COM对象引入的理论上可能的安全性和/或稳定性问题):

虽然这是关于SQL Server的一个解释,但在Windows上也可能出现类似的问题

您可以通过编写+安装.NET程序集将此转换的逻辑放入您的SQL Server中,该程序集公开了您可以调用以进行转换的存储过程... .NET程序集依次访问该COM对象。 。如何看待http://www.sqlteam.com/article/writing-clr-stored-procedures-in-charp-introduction-to-charp-part-1

MSDN参考链接是http://msdn.microsoft.com/en-us/library/ms131094.aspx

答案 1 :(得分:0)

到目前为止,最快的方式是在SQL代码本身中执行更新:

UPDATE T1
SET col2 = [some function based on col1]

(请注意,根据数据库平台,这可能会破坏事务日志。对于MS SQL,具体而言,我建议您更小批量更新,一次可能更新行数为100k行)

如果功能逻辑太复杂,那么请确保您根据主键发布所有500万次更新:

UPDATE T1
SET col2 = @newval
WHERE tableID = @id

答案 2 :(得分:0)

这就是内存中的大量数据。我建议尽可能从COM DLL中提取较小批量的记录中的数据并处理它们。使用PLinq to objects可以最大限度地提高处理器使用率。在这两者之间你应该能够找到一种运作良好的快乐媒体。

答案 3 :(得分:0)

您真的需要使用新值更新col2吗?

如果每一行都获得了smmae值,我会把它写入一个单行的表中,当你需要返回结果时,只需将该行交叉连接。

像这样:

update t2 
set col2 = 1234 -- the computed value over all rows in t1

select t1.col1, 
       t2.col2 
from   t1
       cross join t2 -- t2 only has 1 row

更新相对昂贵,写一行比写500万便宜得多。

否则我会将磨机放在木材所在的位置,因此如果可能请使用TSQL。那么500万不是一个大问题,你可以在服务器上处理它们还是需要在网络上拖动它们?在最后一种情况下,它确实加起来。

Rgds Gert-Jan

答案 4 :(得分:0)

执行这些操作时,您是否希望用户等到它们结束?或者你可以在后台运行这个任务吗?也许甚至在一些预定的处理期间每晚?如果后者是真的,您可以使用您的方法并简单地执行所有数百万次更新,只需确保您不要让用户等待操作完成。否则,您真的需要考虑将所有更新逻辑移植到数据库中的方法。

因此,根据要求,选项将是:

1)启动一个单独的线程(甚至几个线程)来执行更新,而主线程将返回给用户类似“长时间操作运行。请稍后再回到此页面以查看其状态”

2)在一个单独的过程中每晚运行更新

3)重新组织项目,以便您可以在数据库中执行更新。

<强>更新

我看到你经常说你无法将更新逻辑移植到数据库中。如果您不负责项目架构,您是否可以影响管理层重组整个项目?如果需要这样的操作,它看起来像一个糟糕的架构。

答案 5 :(得分:0)

一些基本指示:

  1. 使用DataReader,而不是DataSet。 DataSet的内存开销可能会给这么多行带来麻烦
  2. 如果可能,请在多个线程中并行运行计算部分。你可以使用TPL来做到这一点,但是因为你使用的是COM组件,所以从多个线程访问它可能会有一些问题。请咨询COM专家(或打开另一个SO问题),了解如何确定您的COM组件是否是线程安全的。
  3. 在计算结果时不要打开单个大型事务。如果适合您的语义,请使用“with(nolock)”提示。这有助于防止您的任务影响其他读者/作者。

答案 6 :(得分:0)

如果这是一次性交易,则将您的500万条记录转储到文件中。对文件运行逻辑以生成新记录。转储和文件逻辑应该很快,而不是那么耗时。然后BULK将更新的数据插入到临时表中。

此时,弃用上一个表并使staging表成为具有一些DDL语句的真实表,以放入适当的索引,FK等。

这将是处理此数量记录的最快方法。还有其他任何东西,它可能需要至少几天来处理所有事情。