事务隔离级别快照与截断?


10

我希望有人可以阐明我在SNAPSHOT隔离与TRUNCATE上没有想到的这种行为。

数据库:允许快照隔离= True;读取已提交快照快照= False。

Procedure1(从具有大量连接的长时间运行的复杂SELECT替换表foo的内容):

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

Procedure2(从表foo中读取):

SET TRANSACTION ISOLATION LEVEL SNAPSHOT; 
SELECT * FROM foo;

如果在执行Procedure2的同时正在运行Procedure1,则过程2将等待LCK_M_SCH_S(根据sp_WhoIsActive)等待,直到Procedure1完成。而当Procedure2确实完成时,它将引发此异常:

快照隔离事务在数据库'DatabaseName'中失败,因为自该事务开始以来,该语句访问的对象已由另一个并发事务中的DDL语句修改。不允许这样做,因为未对元数据进行版本控制。如果同时进行元数据更新和快照隔离,则可能导致不一致。

但是,Microsoft并未将TRUNCATE列为SNAPSHOT隔离下不允许的DDL语句:http : //msdn.microsoft.com/zh-cn/library/bb933783.aspx

显然,我并没有正确理解某些东西,因为我希望程序2的最佳情况会在TRUNCATE之前立即返回表中最近提交的数据,或者最坏的情况是被程序1阻止,然后返回程序的新内容。表。你能帮我吗?


您可以改用DELETE FROM foo吗?那不会放置模式锁。
SqlACID 2014年

确实,DELETE FROM是我解决此问题的方法。我也对为什么收到错误(仅在Procedure1返回之后)感兴趣。
Mark Freeman

Answers:


19

列出的'DDL'操作列表并不全面(并且TRUNCATE TABLE不是该列表中唯一的遗漏)。无论TRUNCATE TABLEDML或者DDL是SQL Server一个充满问题,对辩论双方有说服力的例子,和条目联机丛书中的两种方式。

从快照隔离事务的角度来看,truncate具有取得Sch-M的本质,它解释了阻塞(因为RCSI并且SI仍然获取Sch-S)。并且还会由于内部原因*破坏内部元数据版本,从而导致错误3961。

因此,您所看到的行为是预期的,只是没有很好地记录在案。

* TRUNCATE TABLE的当前实现不会生成行版本。碰撞元数据版本是确保正确行为的最简单方法。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.