使用SQL更新250k行的更快方法

时间:2010-04-23 00:36:12

标签: c# sql ado.net

我需要在表上更新大约250k行,并且每个要更新的字段将具有不同的值,具体取决于行本身(不是基于行ID或键计算的,而是根据外部计算)。

我尝试使用参数化查询,但事实证明它很慢(我仍然可以在SQL Server 2008中尝试使用表值参数SqlDbType.Structured,但我想有一个通用的方法来执行它在几个数据库上,包括MySql,Oracle和Firebird)。

制作大量的个人更新也很慢(比使用参数化查询进行数千次单独调用(往返!)快2倍)

如何创建临时表并运行加入我的表和tmp的更新?会更快地运作吗?

6 个答案:

答案 0 :(得分:7)

“慢”的速度有多慢?

这个问题的主要问题是它会在数据库的日志文件中创建一个巨大的条目(如果在更新过程中出现电源故障,数据库需要记录每个操作,它可以在发生故障时回滚)。这很可能是“缓慢”的来源,而不是其他任何东西(尽管显然有如此多的行,还有其他方法可以使事情效率低下[例如,每次更新一次DB往返会非常缓慢] ,我只是说,一旦你消除了明显的事情,你仍然会发现它很慢。)

有几种方法可以更有效地完成它。比如,一个是以块的形式进行更新,一次1000行。这样,数据库就会写出许多小的日志条目,而不是一个非常庞大的日志条目。

另一种方法是关闭 - 或者“关闭” - 数据库在更新期间的日志记录。例如,在SQL Server中,您可以将Recovery Model设置为“简单”或“批量更新”,这会大大加快速度(请注意,如果出现电源故障,您会面临更大风险)更新)。

编辑为了进一步扩展,可能首先实际执行查询的最有效方法是将所有新行的BULK INSERT放入临时表中,然后从那里做一个现有表格的UPDATE(或者如上所述,以1000块为单位进行UPDATE)。我的大多数答案都是在你实现它之后解决这个问题:你仍然会发现它很慢......

答案 1 :(得分:3)

如果可能,请调用存储过程

答案 2 :(得分:2)

如果更新的列是您可以

的索引的一部分
  • 删除这些索引
  • 进行更新
  • 重新创建索引。

如果您需要这些索引来检索数据,那么它无济于事。

答案 3 :(得分:1)

您应该使用SqlBulkCopy并设置KeepIdentities标志。

作为SqlTransaction的一部分,执行查询以选择所有需要更新的记录,然后删除它们,返回那些选定(现在已删除)的记录。一次性将它们读入C#。在内存中更新C#端的记录,现在您已经缩小了选择范围,然后SqlBulkCopy更新了那些更新的记录,键和所有记录。并且不要忘记提交交易。这是更多的工作,但速度非常快。

答案 4 :(得分:0)

这就是我要做的事情:

  1. 检索整个表格,即从外部计算/检索/查找/生成更改所需的列
  2. 计算/产生这些变化
  3. 将批量插入内容运行到临时表,上传服务器端所需的信息以进行更改。这将需要您想要更改的所有行的关键信息+新值。
  4. 在服务器上运行SQL,将新值从临时表复制到生产表中。
  5. 优点:

    • 运行服务器端的最后一步比运行大量的单个SQL更快,因此您将在更短的时间内锁定有问题的表
    • 像这样批量插入很快

    缺点:

    • 数据库中需要额外的空间用于临时表
    • 生成更多日志数据,同时记录批量插入和对生产表的更改

答案 5 :(得分:0)

以下内容可能会使您的更新速度变慢:

  • 通过参数化查询逐个执行更新
    • 解决方案:在一个声明中更新
  • 大型事务创建大日志条目
  • 更新索引(RDBMS将在每行之后更新索引。如果更改索引列,则在大型表上可能会非常昂贵)
    • 如果可以,请在更新前删除索引并在
    • 之后重新创建它们
  • 更新具有外键约束的字段 - 对于每个插入的记录,RDBMS将查找适当的密钥
    • 如果可以,请在更新前禁用外键约束,并在更新后启用它们
  • 触发器和行级检查
    • 如果可以,请在更新前禁用触发器,并在
    • 之后启用它们