Sch-M WAIT阻止SQL Server 2014中的Sch-S,但不阻止SQL Server 2008 R2?


11

最近,我们将生产实例从SQL 2008 R2迁移到了全新的SQL 2014服务器。我们通过使用Service Broker发现了一个有趣的场景。考虑Broker Enabled = true带有MyService和的数据库MyQueue。在此队列上禁用了毒药消息处理。队列中至少有2条活动会话与消息。

在一个进程(SPID 100)中执行:

BEGIN TRANSACTION;
DECLARE @conversation_group_id UNIQUEIDENTIFIER;
RECEIVE TOP (1) @conversation_group_id = conversation_handle FROM MyQueue;

请注意,我们保持交易未结。想象这是一个.NET程序,它在某些外部资源上等待了很长时间。通过sys.dm_tran_locks我们看到,此SPID已被授予队列上的IX锁。

| type   | resource_id | mode | status | spid |
| OBJECT | 277576027   | IX   | GRANT  | 100  |

在一个单独的进程(SPID 101)中执行五次

BEGIN TRANSACTION;
DECLARE @conversation_group_id UNIQUEIDENTIFIER;
RECEIVE TOP (1) @conversation_group_id = conversation_handle FROM MyQueue;
ROLLBACK TRANSACTION;

这里的关键是我们将交易回滚五次。这将触发内置的“ 毒药消息处理”背景逻辑。尽管队列没有被禁用(因为它被配置为不禁用),但是后台任务仍在尝试执行工作并触发broker_queue_disabled事件。因此,如果现在sys.dm_tran_locks再次查询,我们将看到一个其他的SPID(与关联BRKR TASK)正在等待Sch-M锁。

| type   | resource_id | mode  | status | spid |
| OBJECT | 277576027   | IX    | GRANT  | 100  |
| OBJECT | 277576027   | Sch-M | WAIT   | 36   |

到目前为止,一切都有意义。

最后,在另一个进程(SPID 102)上,尝试使用该队列发送到服务:

BEGIN TRANSACTION;
DECLARE @ch uniqueidentifier;
BEGIN DIALOG @ch FROM SERVICE [MyService] TO SERVICE 'MyService';
SEND ON CONVERSATION @ch ('HELLO WORLD');

SEND命令被阻止。如果再看一遍,sys.dm_tran_locks就会发现此过程正在等待Sch-S锁。执行后,sp_who2我们发现SPID 102被SPID 36阻止。

| type   | resource_id | mode  | status | spid |
| OBJECT | 277576027   | IX    | GRANT  | 100  |
| OBJECT | 277576027   | Sch-M | WAIT   | 36   |
| OBJECT | 277576027   | Sch-S | WAIT   | 102  |

为什么Sch-S锁在同样等待的Sch-M锁上等待?

此行为在SQL 2008 R2中完全不同!使用完全相同的方案,在我们即将停用的2008R2实例上运行,最后的批处理(包括SEND命令)不会被等待的Sch-M锁阻塞。

SQL 2012或2014中的锁定行为是否已更改?是否可能有一些数据库或服务器设置可能会影响此锁定行为?


听起来像是一个可能的错误。您是否已应用最新的SP和CU?
Max Vernon 2014年

1
@MaxVernon,我们正在运行12.00.2370
Joseph Daigle,

3
您正在使用与启动程序和目标相同的服务。的SEND块同时检查引发剂队列。SEND不会阻塞目标队列,只会反弹并sys.transmission_queue用于投放。如果将两者分开(总是一个好主意),则不会有问题。
Remus Rusanu 2014年

1
谢谢@RemusRusanu。尽管此示例部分旨在说明已更改的行为,但您的提示是我们在设计服务和队列时要牢记的提示。
约瑟夫·戴格尔,2014年

Answers:


17

在SQL Server 2008 R2和SQL Server 2012之间的行为确实发生了变化。2008 R2的实现与已记录的“宽松的FIFO”语义不一致:

锁以轻松的先进先出(FIFO)方式授予。尽管顺序不是严格的FIFO,但它保留了所需的属性,例如避免饥饿,并可以减少不必要的死锁和阻塞。

如果请求的模式与授予的请求的联合和挂起的请求的模式不兼容,那么请求者尚未拥有资源锁定的新锁定请求将被阻止。

仅当请求的模式与所有授予的模式的并集不兼容时,转换请求才会被阻塞,但最初授予转换请求本身的模式除外。

在2008 R2中,Sch-S尽管新的锁定请求与已授予和等待的请求的并集不兼容,但仍授予了新的锁定请求,这可能会导致锁定不足。在2012年,Sch-S锁定请求被阻止。

下面的复制脚本使用常规表而不是Service Broker队列:

-- Session 1
CREATE TABLE dbo.LockTest (col1 integer NULL);

INSERT dbo.LockTest (col1) VALUES (1);

BEGIN TRANSACTION;

-- Will hold row-X, Pag-IX, and Tab-IX
INSERT dbo.LockTest (col1) VALUES (2);

-- Session 2
-- Blocked waiting on Sch-M
TRUNCATE TABLE dbo.LockTest;

-- Session 3
-- Takes Sch-S only
-- Not blocked in 2008 R2
SELECT * FROM dbo.LockTest AS LT WITH (READUNCOMMITTED);

总之,2008 R2的行为不符合设计。该问题已在SQL Server 2012中修复。

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.