
如果你在SSMS的“对象资源管理器”中看到提示挂起或锁请求超时,这几乎肯定是由模式修改锁(SCH-M)引起的。通常 SCH-M 锁不会导致问题,因为它们的周期很短。但是,如果你在长事务中进行架构更改,那么你在SSMS的对象资源管理器中将不可访问相应的对象列表。
下面将介绍一些可能导致这种情况发生的不同示例,要运行它们首先运行以下脚本来设置测试数据库
CREATE DATABASE MySchemaLocksGOUSE MySchemaLocksGOCREATE TABLE Blah(Id INT)CREATE NONCLUSTERED INDEX ndx_blah ON Blah(id)
删除数据加载的索引
这个问题的最常见,原因是在长时间运行的事务中删除索引并在之后重新创建它们。
BEGIN TRANDROP INDEX ndx_blah ON Blah
此时,我们打开一个事务并删除索引。它现在正在运行一个长查询来加载新数据以保持 SCH-M 锁打开。如果你现在尝试在 SSMS 中展开表节点,将提示如下

在此事务完成之前,架构将被锁定,SSMS 将无法访问列表。如果你运行 ROLLBACK,则 SSMS 将能够再次运行访问。对于这种情况,我们建议在加载数据的事务之外删除并重新创建索引。在最佳情况下,始终将架构更改保留在最短的事务中。
创建临时表
在长事务中创建或删除临时表,与创建或删除索引是相同的。
BEGIN TRANCREATE TABLE tst (blah INT)
和之前一样,尝试在 SSMS 中扩展表节点

此时运行 ROLLBACK,列表将正常访问。
现在我们使用临时表的情况。
BEGIN TRANCREATE TABLE #tst (blah INT)

其他数据库列表打开是正常的,因为架构修改不是在我们的数据库中进行,而是在 TempDB 中进行的。现在尝试在对象资源管理器中扩展 TempDB 的表节点

可以看到错误提示,临时表将它们的 SCH-M 锁放在 TempDB 上。
其他原因
以上两种情况是我们见过最常见的原因,因为它们通常都是在长时间运行的数据作业中运行。但是几乎任何模式修改都可能导致这种情况,例如 ALTER TABLE、ALTER INDEX、CREATE INDEX 等。
SCH-M 锁也会导致用户查询出现各种问题。运行的大多数查询都采用架构稳定性锁 (SCH-S),这将被阻塞并等待 SCH-M 锁。因此,应尽可能短的时间内保持 SCH-M 锁打开。




