当你查看DMV sys.dm_tran_locks时,你会看到那个需要共享锁(Shared Lock(S))的会话需要等待。这个会话会永远等待。我刚才就说过:“部分在线”……
1 SELECT * FROM sys.dm_tran_locks
当我们执行带有锁优先级(Lock Priority)的在线索引重建时,有趣的事情发生了:
1 -- Perform an Online Index Rebuild 2 ALTER INDEX idx_Col1 ON Foo REBUILD 3 WITH 4 ( 5 ONLINE = ON 6 ( 7 WAIT_AT_LOW_PRIORITY 8 ( 9 MAX_DURATION = 1, 10 ABORT_AFTER_WAIT = SELF 11 ) 12 ) 13 ) 14 GO |
在这个情况下,我们的ALTER INDEX语句会等待1分钟(MAX_DURATION),然后语句本身取消了(ABORT_AFTER_WAIT)。
如果你在这里指定了BLOCKERS选项,那么阻塞的会话就会回滚。当我们同时(在1分钟期间)查看DMV sys.dm_tran_locks,我们看到了有趣的东西:
从图中可以看到,SQL Server这里请求一个LOW_PRIORITY_WAIT的状态。因此3个请求状态(GRANT,WAIT,CONVERT)有了第4个选项:LOW_PRIORITY_WAIT。当我们查看DMV sys.dm_os_waiting_tasks时,事情变得有意思(59是执行语句的会话ID):
1 SELECT * FROM sys.dm_os_waiting_tasks WHERE session_id='59'
在线索引重建操作的等待会话报告了一个新的等待类型LCK_M_S_LOW_PRIORITY。这意味着当在线索引重建操作被阻塞时,我们可以从服务器级别(sys.dm_os_wait_stats)的等待统计信息里获得——不错!
但是LCK_M_S_LOW_PRIORITY并不是新的等待类型。在SQL Server 2014里,当你查看DMV sys.dm_os_wait_stats时,会看到21个新的等待类型:
1 SELECT * FROM sys.dm_os_wait_stats WHERE wait_type LIKE '%LOW_PRIORITY%'
LCK_M_SCH_S_LOW_PRIORITY
LCK_M_SCH_M_LOW_PRIORITY
LCK_M_S_LOW_PRIORITY
LCK_M_U_LOW_PRIORITY
LCK_M_X_LOW_PRIORITY
LCK_M_IS_LOW_PRIORITY
LCK_M_IU_LOW_PRIORITY
LCK_M_IX_LOW_PRIORITY
LCK_M_SIU_LOW_PRIORITY
LCK_M_SIX_LOW_PRIORITY
LCK_M_UIX_LOW_PRIORITY
LCK_M_BU_LOW_PRIORITY
LCK_M_RS_S_LOW_PRIORITY
LCK_M_RS_U_LOW_PRIORITY
LCK_M_RIn_NL_LOW_PRIORITY
LCK_M_RIn_S_LOW_PRIORITY
LCK_M_RIn_U_LOW_PRIORITY
LCK_M_RIn_X_LOW_PRIORITY
LCK_M_RX_S_LOW_PRIORITY
LCK_M_RX_U_LOW_PRIORITY
LCK_M_RX_X_LOW_PRIORITY
所有主要的等待类型(LCK_M_*)都有额外的锁优先级等待类型。这个非常酷,也非常强大,因为你很容易从中可以跟踪到为什么在线重建索引操作被阻塞。另外,对于分区切换(Partition Switching)也适用同样的技术(锁优先级(Lock Priorities)),因为在切换期间,操作也要在2个表(原表,目标表)上获取架构修改锁(Schema Modification Lock (Sch-M))。
我希望这篇文章可以让你理解SQL Server 2014里的锁优先级(Lock Priorities),还有为什么SQL Server里的“在线”操作实际上只是“部分在线”。