Параллелизм SQL Server - PullRequest
       2

Параллелизм SQL Server

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

Я задал два вопроса сразу в моей последней теме, и на первый был дан ответ. Я решил пометить оригинальную ветку как ответившую и повторить второй вопрос здесь. Ссылка на оригинальный поток, если кто-то хочет: Обработка проблем параллелизма SQL Server

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

Шаги, которые мне нужно выполнить:

1) Посмотрите количество записей в таблице A

2) Выполнить некоторую бизнес-логику, которая готовит одну строку, которая вставляется в таблицу B

3) Обновить записи, выбранные на шаге 1), чтобы они указывали на вновь созданную запись в таблице B

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

Ответы [ 4 ]

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

В SQL Server 2008 это может быть обработано с помощью отфильтрованного уникального индекса:

CREATE UNIQUE INDEX ix_MyIndexName ON MyTable (FKField) WHERE FkField IS NOT NULL

Это потребует, чтобы все ненулевые значения были уникальными, и база данных обеспечит это для вас.

2 голосов
/ 26 сентября 2011

Использование вычисляемого столбца

ALTER TABLE MyTable ADD
   OneNonNullOnly AS ISNULL(FkField, -PkField)

CREATE UNIQUE INDEX ix_OneNullOnly ON MyTable (OneNonNullOnly);

Предполагает:

  • FkField является числовым
  • нет конфликта значений FkField и -PkField
2 голосов
/ 26 сентября 2011

Способ моделирования уникального отфильтрованного индекса 2005 года для целей ограничения -

CREATE VIEW dbo.EnforceUnique
WITH SCHEMABINDING
AS
SELECT FkField
FROM dbo.TableB
WHERE FkField IS NOT NULL

GO

CREATE UNIQUE CLUSTERED INDEX ix ON dbo.EnforceUnique(FkField)

Соединения, которые обновляют базовую таблицу, должны иметь правильные параметры SET, но если вы не используете параметры не по умолчанию, это будет иметь место в любом случае в SQL Server 2005 (ARITH_ABORT раньше был проблемой в 2000 году)

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

Решили пойти со следующим:

1) Начать транзакцию

2) UPDATE tableA SET foreignKey = -1 OUTPUT inserted.id INTO #tempTable FROM (business logic) WHERE foreignKey is null

3) If @@rowcount > 0 Then

3a) Создать запись в таблице 2.

3b) Идентификатор захвата вновь созданной записи с использованием scope_identity()

3с) UPDATE tableA set foreignKey = IdOfNewRecord FROM tableA INNER JOIN @tempTable ON tableA.id = tempTable.id

Поскольку я записываю нежелательную информацию в поле внешнего ключа на шаге 2), эти строки блокируются, и никакие параллельные транзакции их не трогают. Первая транзакция свободна для создания записи. После фиксации транзакции заблокированная транзакция выполнит запрос на обновление, но не будет захватывать ни одну из исходных строк из-за предложения WHERE, учитывающего только поля NULL foreignKey. Если строки не возвращаются (@@rowcount = 0), текущая транзакция завершается без создания записи в таблице B и возвращает клиенту какое-то сообщение об ошибке. (например, Error: Record already exists)

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