如何避免UPDATE语句在更新大量记录时锁定整个表

Hap*_*own 7 t-sql sql-server

我对锁和提示相当新.

我有一张非常频繁SELECTINSERT操作的桌子.该表有1100万条记录.

我已经添加了一个新列,我需要将数据从同一个表中的现有列复制到新列.

我打算使用ROWLOCK提示来避免将锁升级到表级锁并阻止表上的所有其他操作.例如:

UPDATE 
    SomeTable WITH (ROWLOCK)
SET
    NewColumn = OldColumn
Run Code Online (Sandbox Code Playgroud)

问题:

  1. NOLOCK不是ROWLOCK?请注意,一旦将记录插入表中,OldColumn的值就不会更改,因此NOLOCK不会导致脏读.
  2. 难道NOLOCK甚至意义在这种情况下,因为SQL Server将不得不反正获得更新锁UPDATE.
  3. 有没有更好的方法来实现这一目标?

我知道要避免使用提示,SQL Server通常会做出更明智的选择,但我不希望在此更新期间锁定表.

Hap*_*own 7

我采用了 @pacreely 的批量更新方法(请参阅他对此问题的回答)并创建了一个update...top变体。我添加了 (rowlock) 提示,告诉 SQL Server 将锁保持在行级别。

有关详细信息,请参阅更新...顶部order by另请注意,在使用topin updateinsertmerge、语句时不能使用delete,因此引用的行不会按任何顺序排列。

declare @BatchSize  int = 1000
declare @RowCount   int = @BatchSize

while @RowCount > 0
begin
    update top (@BatchSize) SomeTable with (rowlock)
    set NewColumn = OldColumn
    where 
        NewColumn <> OldColumn      or
        (
            NewColumn is null       and
            OldColumn is not null
        )
    select @RowCount = @@rowcount
end
Run Code Online (Sandbox Code Playgroud)


pac*_*ely 6

尝试批量更新。

DECLARE @Batch INT = 1000
DECLARE @Rowcount INT = @Batch


WHILE @Rowcount > 0
    BEGIN
        ;WITH CTE AS 
        (
            SELECT TOP (@Batch) NewColumn,OldColumn 
            FROM SomeTable 
            WHERE NewColumn <> OldColumn
                  OR (NewColumn IS NULL AND OldColumn IS NOT NULL)
        )
        UPDATE cte
            SET NewColumn = OldColumn;
        SET @Rowcount = @@ROWCOUNT
    END
Run Code Online (Sandbox Code Playgroud)