对一个非常大的表进行批量更新






3.12/5 (7投票s)
2006年1月24日
2分钟阅读

92660
在生产环境中更新超大表,避免锁定整个表。
我们这些在生产/实时数据库中工作的人,都知道在超大表上运行更新查询的痛苦。这非常成问题,因为它会导致以下情况:
- 锁升级:整个表将被您的应用程序锁定,因此其他用户/应用程序将无法对此表执行 DDL 操作
- TempDB 将变得巨大
- 对表的 更新锁 将阻止其他用户对表进行更改
我写了一个下面的代码片段,它将帮助我们解决上述问题
-- 步骤 1: 声明变量
使用 DBNAME
声明 @counter int
声明 @RowsEffected int
声明 @RowsCnt int
声明 @CodeId int
声明 @Err int
SELECT @COUNTER = 1
SELECT @RowsEffected = 0
/*
步骤 2: 获取我们需要更新现有代码的代码值。在我的情况下,我从一个表中获取它,我们总是可以硬编码它。
*/SELECT @CodeID = CodeID FROM CODE WHERE XXXX ='YYYY'
/*
步骤 3: 开始 while 循环,如果我们有 100,000 条记录,并且在每个循环中更新 5,000 条记录,因此总循环次数将是 100,000/5000,即 20
*/
WHILE ( @COUNTER > 0)
BEGIN
SET ROWCOUNT 5000
-- 注意: SET ROWCOUNT 5000 只会选择前 5000 条记录 */
/*更新表 */
UPDATE Table
SET CodeID= @CodeID
WHERE Codeid = @OldCode
SELECT @RowsCnt = @@ROWCOUNT ,@Err = @@error
IF @Err <> 0
BEGIN
打印 '更新记录时出现问题'
END
IF @RowsCnt = 0
SELECT @COUNTER = 0
ELSE
/* 增加计数器 */
SELECT @RowsEffected = @RowsEffected + @RowsCnt
打印 '受影响的总行数:'+convert(varchar,@RowsEffected)
/*延迟循环 10 秒,以便更新完成*/
等待延迟 '00:00:10'
END
--步骤 4: 检查是否所有记录都已更新。 IF EXISTS ( SELECT CodeID
/* ------将行计数设置为默认值 ----*/
FROM Table (NOLOCK)
WHERE CodeID = @OldCodeid
)
BEGIN
打印 ('并非所有记录都已更新,存在一些问题,请联系开发人员')
END
BEGIN
打印 ('所有记录已成功更新!!!!')
END SET ROWCOUNT 0