Как избежать блокировки инструкции UPDATE всей таблицы при обновлении большого количества записей
Я довольно новичок в замках и подсказках.
у меня есть таблица с очень частыми SELECT
и INSERT
операции. В таблице 11 миллионов записей.
я добавил к нему новый столбец, и мне нужно скопировать данные из существующего столбца в той же таблице в новый столбец.
Я планирую использовать ROWLOCK
подсказка, чтобы избежать эскалации блокировки до блокировки уровня таблицы и блокировки всех других операций на столе. Для пример:
UPDATE
SomeTable WITH (ROWLOCK)
SET
NewColumn = OldColumn
вопросы:
- Б
NOLOCK
вместоROWLOCK
? Обратите внимание, что после вставки записей в таблицу значение OldColumn не изменяется, поэтомуNOLOCK
не будет вызывать грязные чтения. - тут
NOLOCK
даже имеет смысл в этом случае, потому что SQL Server должен был бы в любом случае получить блокировки обновления дляUPDATE
. - есть ли лучший способ достичь этого?
Я знаю, намеки должны быть избегается и 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 сохранял блокировки на уровне строк.
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