SNAPSHOT УРОВНЯ ИЗОЛЯЦИИ ТРАНЗАКЦИИ против TRUNCATE?

10

Я надеюсь, что кто-то может пролить некоторый свет на это поведение, которого я не ожидал в отношении изоляции SNAPSHOT против TRUNCATE.

База данных: Разрешить изоляцию моментального снимка = True; Считано, зафиксированный снимок включен = False.

Процедура 1 (заменяет содержимое таблицы foo из долго выполняющегося комплекса SELECT множеством объединений):

BEGIN TRAN; 
TRUNCATE TABLE foo; 
INSERT INTO foo SELECT...; 
COMMIT;

Процедура2 (читает из таблицы foo):

SET TRANSACTION ISOLATION LEVEL SNAPSHOT; 
SELECT * FROM foo;

Если Процедура1 выполняется во время выполнения Процедуры2, Процедура2 задерживается с ожиданием LCK_M_SCH_S (согласно sp_WhoIsActive) до завершения Процедуры1. И когда процедура2 завершается, возникает это исключение:

Не удалось выполнить транзакцию изоляции моментального снимка в базе данных «DatabaseName», поскольку объект, к которому обращается оператор, был изменен оператором DDL в другой параллельной транзакции с момента начала этой транзакции. Это запрещено, поскольку метаданные не являются версионными. Одновременное обновление метаданных может привести к несогласованности при смешивании с изоляцией моментального снимка.

Однако Microsoft не перечисляет TRUNCATE как оператор DDL, не разрешенный в изоляции SNAPSHOT: http://msdn.microsoft.com/en-us/library/bb933783.aspx

Понятно, что я что-то не правильно понимаю, так как я ожидал, что лучший вариант процедуры2 немедленно возвращает самые последние зафиксированные данные из таблицы перед TRUNCATE или наихудший случай задержки процедурой1 и затем возвращается новое содержимое стол. Вы можете помочь?

Марк Фриман
источник
Можете ли вы использовать вместо этого DELETE FROM foo? Это не приведет к блокировке схемы.
SqlACID
DELETE FROM - это действительно способ, которым я работаю над этим. Меня также интересует, почему я получаю сообщение об ошибке (и только после возврата из процедуры1).
Марк Фриман

Ответы:

19

Список 'DDL'перечисленных операций не является исчерпывающим (и TRUNCATE TABLEне является единственным упущением в этом списке). Является ли TRUNCATE TABLEэто DMLили нет DDLчересчур сложным вопросом в SQL Server, с убедительными примерами по обе стороны дискуссии и с записями в обе стороны в Books Online.

С точки зрения транзакции изоляции моментального снимка, truncate обладает необходимым качеством взятия Sch-Mблокировки , которая объясняет блокировку (потому что RCSIи SIвсе еще получает Sch-Sблокировки ); и это также изменяет внутреннюю версию метаданных (по внутренним причинам *), что приводит к ошибке 3961.

Итак, поведение, которое вы видите, ожидается, но не очень хорошо задокументировано.

* Текущая реализация TRUNCATE TABLE не генерирует версии строк. Изменение версии метаданных - это самый простой способ обеспечить правильное поведение.

Пол Уайт 9
источник