Как избежать блокировки инструкции UPDATE всей таблицы при обновлении большого количества записей

Я довольно новичок в замках и подсказках.

у меня есть таблица с очень частыми SELECT и INSERT операции. В таблице 11 миллионов записей.

я добавил к нему новый столбец, и мне нужно скопировать данные из существующего столбца в той же таблице в новый столбец.

Я планирую использовать ROWLOCK подсказка, чтобы избежать эскалации блокировки до блокировки уровня таблицы и блокировки всех других операций на столе. Для пример:

UPDATE 
    SomeTable WITH (ROWLOCK)
SET
    NewColumn = OldColumn

вопросы:

  1. Б NOLOCK вместо ROWLOCK? Обратите внимание, что после вставки записей в таблицу значение OldColumn не изменяется, поэтому NOLOCK не будет вызывать грязные чтения.
  2. тут NOLOCK даже имеет смысл в этом случае, потому что SQL Server должен был бы в любом случае получить блокировки обновления для UPDATE.
  3. есть ли лучший способ достичь этого?

Я знаю, намеки должны быть избегается и SQL Server обычно делает более разумный выбор, но я не хочу, чтобы таблица была заблокирована во время этого обновления.

3 ответов


попробуйте обновить пакеты.

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

этот вопрос имеет ответ на сайте администраторов базы данных на StackExchange здесь: https://dba.stackexchange.com/questions/127158/how-to-get-sql-insert-and-or-update-to-not-lock-entire-table-on-ms-sql-server


Я взял подход @pacreely (см. Его ответ на этот вопрос) обновления в пакетах и создал update...top вариация. Я добавил подсказку (rowlock), чтобы SQL server сохранял блокировки на уровне строк.

посмотреть обновление...топ!--12--> для сведения. Также обратите внимание, что вы не можете использовать order by при использовании top на update, insert, merge, 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