在IsolationLevel.ReadUncommitted上发出了共享锁。

我读到如果我使用IsolationLevel.ReadUncommitted,查询不应该发出任何锁。然而,当我测试时,我看到了以下的锁: 资源类型:HOBT 请求模式:S(共享) HOBT锁是什么?与HBT(堆或二叉树锁)有关吗? 为什么我仍然会得到一个S锁? 在查询时如何避免共享锁,而不打开隔离级别快照选项? 我正在SQL Server 2008上进行测试,并且快照选项已关闭。查询只执行一个选择操作。 我可以看到需要Sch-S,尽管SQL Server似乎没有在我的锁查询中显示它。为什么它仍然发出共享锁?根据: SET TRANSACTION ISOLATION LEVEL(Transact-SQL) 运行在READ UNCOMMITTED级别的事务不会发出共享锁,以防止其他事务修改当前事务读取的数据。 所以我有点困惑。
2个回答

HOBT锁是什么? HOBT锁是用来保护B树(索引)或表中堆数据页的一种锁定机制。它适用于没有聚集索引的表。 为什么我还会得到S锁呢? 这通常发生在堆上。举个例子,
SET NOCOUNT ON;

DECLARE @Query nvarchar(max) = 
   N'DECLARE @C INT; 
     SELECT @C = COUNT(*) FROM master.dbo.MSreplication_options';

/*Run once so compilation out of the way*/
EXEC(@Query);

DBCC TRACEON(-1,3604,1200) WITH NO_INFOMSGS;

PRINT 'READ UNCOMMITTED';
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
EXEC(@Query);

PRINT 'READ COMMITTED';
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
EXEC(@Query);

DBCC TRACEOFF(-1,3604,1200) WITH NO_INFOMSGS;

输出 READ UNCOMMITTED

Process 56 acquiring Sch-S lock on OBJECT: 1:1163151189:0  (class bit0 ref1) result: OK

Process 56 acquiring S lock on HOBT: 1:72057594038910976 [BULK_OPERATION] (class bit0 ref1) result: OK

Process 56 releasing lock on OBJECT: 1:1163151189:0 

输出 READ COMMITTED

Process 56 acquiring IS lock on OBJECT: 1:1163151189:0  (class bit0 ref1) result: OK

Process 56 acquiring IS lock on PAGE: 1:1:169 (class bit0 ref1) result: OK

Process 56 releasing lock on PAGE: 1:1:169

Process 56 releasing lock on OBJECT: 1:1163151189:0 
根据引用保罗·兰达尔的这篇文章,采取BULK_OPERATION共享HOBT锁的原因是为了防止读取未格式化的页面。

ReadUncommitted隔离级别确实会获取锁。模式稳定性锁在查询执行期间防止被查询的对象被修改。这些锁在所有隔离级别下都会被获取,包括快照和读取已提交的快照(RCSI)。来自锁模式

模式锁

数据库引擎在表数据定义语言(DDL)操作期间使用模式修改(Sch-M)锁,例如添加列或删除表。在持有该锁的时间内,Sch-M锁阻止对表的并发访问。这意味着Sch-M锁会阻塞所有外部操作,直到释放锁为止。

某些数据操作语言(DML)操作,例如表截断,使用Sch-M锁来防止并发操作对受影响的表的访问。

数据库引擎在编译和执行查询时使用模式稳定性(Sch-S)锁。Sch-S锁不会阻塞任何事务锁,包括排他(X)锁。因此,在查询编译期间,其他具有表上X锁的事务仍然可以运行。但是,无法对表执行并发的DDL操作和获取Sch-M锁的并发DML操作。