我的数据库背景主要是Oracle,但我最近一直在帮助完成一些SQL Server工作。我的小组继承了一些SQL服务器DTS包,它们每天都会加载和更新大量数据。目前它在SQL Server 2000中运行,但很快将升级到SQL Server 2005或2008.批量更新运行得太慢。
我注意到代码的一件事是在循环中的过程代码中完成了一些大的更新,因此每个语句只在单个事务中更新表的一小部分。这是在SQL Server中进行更新的合理方法吗?锁定并发会话应该不是问题,因为在批量加载发生时禁用用户对表的访问权限。我搜索了一些,发现一些文章建议以这种方式这样做可以节省资源,并且每次更新提交时都会释放资源,从而提高效率。在Oracle中,这通常是一种糟糕的方法,并且我已经使用单个事务进行非常大的更新,并在Oracle中取得了成功。频繁提交会减慢进程并在Oracle中使用更多资源。
我的问题是,对于SQL Server中的大量更新,使用过程代码,提交许多SQL语句或使用一个大语句来执行整个更新通常是一种好习惯吗?
答案 0 :(得分:2)
抱歉伙计,
以上都没有回答这个问题。它们只是您如何做事的例子。答案是,频繁提交会使用更多资源,但是,在提交点之前不能截断事务日志。因此,如果您的单个跨越事务非常大,则会导致事务日志增长,并且可能会发生频繁,如果未检测到,将导致以后出现问题。此外,在回滚情况下,持续时间通常是原始事务的两倍。因此,如果您的交易在1/2小时后失败,则需要1小时才能回滚,您无法阻止它: - )
我使用过SQL Server2000 / 2005,DB2,ADABAS以及以上所有内容都是如此。我真的不知道Oracle如何以不同的方式工作。
您可以使用bcp命令替换T-SQL,您可以在那里设置批量大小而无需编写代码。
在单个表扫描中发出frequest提交对于使用小处理数运行多个扫描是可以忍受的,因为通常如果需要进行表扫描,即使您只返回一个小子集,也会扫描整个表。
远离快照。快照只会增加IO的数量并竞争IO和CPU
答案 1 :(得分:1)
一般情况下,我发现批量更新更好 - 通常在100到1000之间。这完全取决于表的结构:外键?触发器?或者只是更新原始数据?您需要尝试查看哪种方案最适合您。
如果我使用纯SQL,我会做这样的事情来帮助管理服务器资源:
SET ROWCOUNT 1000
WHILE 1=1 BEGIN
DELETE FROM MyTable WHERE ...
IF @@ROWCOUNT = 0
BREAK
END
SET ROWCOUNT 0
在此示例中,我正在清除数据。如果您可以限制或以其他方式有选择地更新行,这仅适用于UPDATE。 (或者只将xxxx行数插入可以加入的辅助表中。)
但是,请尽量不要一次更新xx百万行。它需要永远,如果发生错误,所有这些行都将被回滚(这将永远需要额外的。)
答案 2 :(得分:0)
一切都取决于。
但是...... 假设您的数据库处于单用户模式或您有表锁(tablockx)对所有相关表,批次可能会表现更差。特别是如果批次强制进行表扫描。
唯一需要注意的是,非常复杂的查询通常会消耗tempdb上的资源,如果tempdb用完了空间(导致执行计划需要一个讨厌的复杂散列连接),你就会陷入困境。
批量工作是一种常见的做法,经常在SQL Server中使用(当它不处于快照隔离模式时)以增加并发性并避免由于死锁导致的大量事务回滚(当更新1000万时,您往往会遇到死锁活动的行表)。
答案 3 :(得分:0)
当您迁移到SQL Server 2005或2008时,您将需要在SSIS中重做所有这些DTS包。我想你会惊喜地发现SSIS的速度有多快。
通常,在SQL Server 2000中,如果整个集合占用表太长时间,则希望以批量记录运行事物。如果您在晚上运行程序包时系统没有用处,您可以使用基于集合的整个数据集插入。逐行总是最慢的方法,所以尽可能避免使用(特别是如果所有行 - 行 - 行插入都在一个巨大的事务中!)。如果你有24小时访问没有停机时间,你几乎肯定需要分批运行。