Проблема изоляции транзакции SQL Server - глобальная переменная - PullRequest
1 голос
/ 08 сентября 2011

SQL Server 2008 R2 (выпуск Data Center - я думаю)

У меня очень специфические требования к базе данных.

Мне нужно вставить строку, помеченную меткой времени [ChangeTimeStamp]. Значение метки времени передается в качестве параметра. Отметка времени должна быть уникальной.

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

declare @maxChangeStamp bigint

set transaction isolation level read committed
begin transaction 
select @maxChangeStamp = MAX(MaxChangeTimeStamp) from TSMChangeTimeStamp

if (@maxChangeStamp > @changeTimeStamp)
    set @maxChangeStamp = @maxChangeStamp + 1   
else 
    set @maxChangeStamp = @changeTimeStamp

update TSMChangeTimeStamp 
set MaxChangeTimeStamp = @maxChangeStamp 
commit

set @changeTimeStamp = @maxChangeStamp

insert statment
  • REPEATABLE READ - вызывает тупик
  • READ COMMITTED - вызывает повторные вставки ключей

@changeTimeStamp - это мой параметр. TSMChangeTimeStamp содержит только одно значение.

Если у кого-то есть хорошая идея, как решить эту проблему, я буду признателен за любую помощь.

Ответы [ 2 ]

3 голосов
/ 08 сентября 2011

Вы не читаете-инкремент-обновление, это не удастся, независимо от того, что вы пытаетесь.Всегда обновляйте и используйте предложение OUTPUT, указав новое значение:

update TSMChangeTimeStamp 
   set MaxChangeTimeStamp  += 1
   output inserted.MaxChangeTimeStamp;

Вы можете захватить выходное значение, если оно вам нужно в T-SQL.Но хотя это будет делать то, что вы просите, вы определенно не хотите делать это, особенно в системе, которая достаточно высокого класса для запуска DC Edition.Генерация следующей временной метки поместит X-блокировку в ресурс временной метки и, таким образом, не позволит каждой другой транзакции генерировать новую временную метку до тех пор, пока текущая транзакция не завершится.Вы добиваетесь полной сериализации работы, когда в данный момент активна только одна транзакция.Спектакль опустится до дна пропасти.

Вы должны пересмотреть свое требование и предложить более подходящее.Поскольку сейчас ваше требование также можно выразить так: «Моя система слишком быстрая, как я могу сделать это действительно очень медленно?».

1 голос
/ 08 сентября 2011

Внутри транзакции оператор SELECT получает общую блокировку, если режим не READ COMMITTED или изоляция моментального снимка. Если оба процесса запускают SELECT одновременно, они оба получают общую блокировку.

Позже оператор UPDATE пытается получить монопольную блокировку (или блокировку обновления). К сожалению, ни один из них не может получить эксклюзивную блокировку, потому что другой процесс имеет общую блокировку.

Попробуйте использовать табличную подсказку WITH (UPDLOCK) в операторе SELECT. Из MSDN:

UPDLOCK

Указывает, что блокировки обновления следует снимать и удерживать до транзакция завершена. UPDLOCK принимает блокировки обновления для операций чтения только на уровне строк или страниц. Если UPDLOCK сочетается с TABLOCK или блокировка на уровне таблицы берется по какой-то другой причине, вместо этого будет установлена ​​эксклюзивная (X) блокировка.

Когда указана UPDLOCK, READCOMMITTED и READCOMMITTEDLOCK подсказки уровня изоляции игнорируются. Например, если уровень изоляции сеанса имеет значение SERIALIZABLE, а запрос указывает (UPDLOCK, READCOMMITTED), подсказка READCOMMITTED игнорируется и транзакция выполняется с использованием уровня изоляции SERIALIZABLE.

Например:

begin transaction
select @maxChangeStamp = MAX(MaxChangeTimeStamp) from TSMChangeTimeStamp with (updlock) 

Обратите внимание, что блокировка обновления может быть переведена в блокировку таблицы, если для вашей таблицы нет индекса ( Microsoft KB статья 179362) .

Явный запрос XLOCK также может работать.

Также обратите внимание, что у вашего оператора UPDATE нет предложения WHERE. Это заставляет UPDATE блокировать и обновлять каждую запись в таблице (если применимо в вашем случае).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...