Операция изоляции моментальных снимков отменена из-за конфликта обновлений

Следующее утверждение:

INSERT INTO dbo.Changes([Content], [Date], [UserId], [CompanyId]) 
  VALUES (@1, @2, @3, @4);
SELECT @@identity;

дает мне эту ошибку SQL 3960:

Операция изоляции моментальных снимков отменена из-за конфликта обновлений. Вы не может использовать изоляцию моментальных снимков для прямого доступа к таблице "dbo.Companies" или косвенно в базе данных "myDatabase" для обновления, удаления или вставки строка, которая была изменена или удалена другой транзакцией. Повторите транзакцию или измените уровень изоляции для update/delete.

Насколько я понял, из сообщения об ошибке я не должен обновлять, удалять или вставлять в таблицу dbo.Companies в то время, когда изменяется другое соединение dbo.Companies.

Но почему это происходит, когда я вставлял новую строку в другую таблицу dbo.Changes (у которой есть внешний ключ для dbo.Companies), и я не удалял ссылочную строку в dbo.Companies, но я просто обновлял строку в dbo.Companies, а не первичный ключ? Это должно работать нормально, не так ли? (Это ошибка в SQL Server?)

ОБНОВЛЕНИЕ:

Таблицы выглядят следующим образом:

dbo.Changes([Id] int PK, [Content] nvarchar, 
  [Date] datetime, [UserId] int, [CompanyId] int -> dbo.Companies.[Id])
dbo.Companies([Id] int PK, [Name] nvarchar)

Выполняется второе обновление:

UPDATE dbo.Companies WHERE [Id] = @1 SET [Name] = @2;

Ответ 1

Похоже, что SQL Server получит блокировки обновлений на любой записи, которую он должен прочитать , даже если он не изменит ее.

Дополнительная информация об этом поток microsoft.public.sqlserver.server:

Без индекса поддержки для CustomerContactPerson утверждение

УДАЛИТЬ ОТ ContactPerson ГДЕ ID = @ID;

Требуется "текущий" прочитайте все строки в CustomerContactPerson, чтобы убедиться, что не являются строками CustomerContactPerson, которые ссылаются на удаленные Строка ContactPerson. С помощью индекса DELETE может определить, что в CustomerContactPerson нет соответствующих строк, не читая строки, затронутые другой транзакцией.

Кроме того, в снимке транзакция - шаблон для чтения данных, которые вы собираетесь преобразовать вокруг и обновление - это делать UPDLOCK при чтении. Это обеспечивает что вы делаете свое обновление на основе "текущих" данных, а не "согласованные" (моментальные снимки) данные, а при выпуске DML это данные не будут заблокированы, и вы не будете перезаписывать другой смена сеанса.

Исправление для нас было добавление индексов к внешним ключам

В вашем примере, я подозреваю, что добавление индекса в Changes.CompanyId поможет. Я не уверен, что это настоящее решение. Может ли оптимизатор SQL Server не использовать индекс?

Ответ 2

SQL Server может видеть обновление зависимой таблицы, которая МОЖЕТ модифицировать поведение вставки... кажется мне справедливым, поскольку SQL не может угадать, какая другая логика может зависеть от столбца [name] (триггеры и т.д.),

если ваши приложения реализуют логику повтора логики блокировки, вы можете изменить их для обработки ошибки № 3960 так же, как ошибка № 1205 и автоматически повторить...