Обработка проблем параллелизма SQL Server - PullRequest
2 голосов
/ 25 сентября 2011

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

1) Установить уровень изоляции транзакции на сериализуемый

2) ВЫБЕРИТЕ ИД С меткой UniqueIdTable WHERE = @ inputLabel

3) ОБНОВЛЕНИЕ UniqueIdTable SET id = id + 1 WHERE label = @ inputLabel

4) Вернуть идентификатор, полученный в 2)

Но действительно ли это безопасно? Возможно ли одновременное выполнение двух потоков до шага 2), даже с сериализуемой изоляцией? Насколько я понимаю, самый высокий уровень изоляции гарантирует только то, что одна транзакция будет выполняться без появления фантомных строк или изменения данных из других потоков. В этом случае два одновременных вызова функции GetID могут возвращать одно и то же значение.

Я что-то неправильно понимаю об уровнях изоляции? Как я могу гарантировать, что этого не произойдет?


У меня есть еще одна проблема, с которой мне нужно разобраться. Предположим, у меня есть таблица с полем, в котором хранятся внешние ключи для второй таблицы. Первоначально записи в первой таблице не имеют соответствующей записи во второй таблице, поэтому я сохраняю NULL в этом поле. Теперь в какой-то момент пользователь запускает операцию, которая сгенерирует запись во второй таблице и на нее ссылается первая таблица. Это всегда отношение один-к-одному, поэтому, если два пользователя одновременно пытаются сгенерировать запись, создается и связывается одна запись, а другой пользователь получает сообщение о том, что запись уже существует. Как я могу убедиться, что дубликаты не создаются в параллельной среде?

Ответы [ 3 ]

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

Вы можете увеличить и для извлечения идентификатора в операторе обновления, используя output .

update UniqueIdTable
set ID = ID + 1
output deleted.ID
where label = @inputLabel
0 голосов
/ 26 сентября 2011

Создайте пользовательскую таблицу в некоторой базе данных, где вы можете включить поле инкрементного идентификатора.Любое приложение, которому нужен этот номер, создаст запись и будет использовать возвращаемое значение.Даже если вы возьмете это значение и не примените его к таблице, где оно вам нужно, оно все равно будет уникальным, даже если вы примените его через год.

0 голосов
/ 25 сентября 2011

Я думаю, вы правы, что два потока могут читать одно и то же значение на шаге 2. Я могу подумать о двух альтернативах:

  1. Добавить предикат для id в операторе обновления, чтобыон обновляется, только если значение не изменилось.Если обновление не обновляет какую-либо запись (не знаю, как проверить в SQL Server, но должно быть возможно), попробуйте снова выполнить операцию.

  2. Сначала выполните оператор обновления.Только один поток сможет выполнить.Затем выберите обновленное значение.

У меня есть два других предложения

  1. Сделайте это в отдельной транзакции, чтобы длительная транзакция не блокироваласьдругой

  2. Зарезервировать локальный для потока блок на прикладном уровне.Увеличьте на большое значение, затем 1 и используйте идентификаторы из локального блока потока.Это уменьшит количество обращений к серверу и обновлений таблицы

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