O WA-Sch-M bloqueia o Sch-S no SQL Server 2014, mas não no SQL Server 2008 R2?

11

Recentemente, migramos nossas instâncias de produção do SQL 2008 R2 para novos servidores SQL 2014. Aqui está um cenário interessante que descobrimos com o uso do Service Broker. Considere um banco de dados Broker Enabled = truecom MyServicee MyQueue. O tratamento de mensagens suspeitas está desabilitado nesta fila. Existem pelo menos 2 conversas ativas com mensagens na fila.

Em um processo (SPID 100), execute:

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

Observe que deixamos a transação aberta. Imagine que é um programa .NET que está aguardando muito tempo em algum recurso externo. Via sys.dm_tran_locksvemos que esse SPID recebeu um bloqueio IX na fila.

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

Em um processo separado (SPID 101), execute cinco vezes :

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

A chave aqui é que estamos revertendo a transação cinco vezes . Isso aciona a lógica de fundo de manipulação de mensagens de veneno incorporada . Embora a fila não seja desabilitada (porque está configurada para não desabilitar), uma tarefa em segundo plano ainda está tentando executar o trabalho e disparar um broker_queue_disabledevento. Então, agora, se consultarmos sys.dm_tran_locksnovamente, veremos um SPID diferente (associado a BRKR TASK) aguardando um bloqueio Sch-M.

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

Até agora, tudo faz sentido.

Finalmente, em um processo diferente (SPID 102), tente ENVIAR para um serviço usando essa fila:

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

O SENDcomando está bloqueado. Se olharmos novamente sys.dm_tran_locks, vemos que esse processo está aguardando um bloqueio Sch-S. Ao executar sp_who2, descobrimos que o SPID 102 está bloqueado pelo 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  |

Por que um bloqueio Sch-S aguarda um bloqueio Sch-M que também está aguardando?

Esse comportamento é completamente diferente no SQL 2008 R2! Usando exatamente esse mesmo cenário, executando em nossas instâncias 2008R2 ainda a serem descomissionadas, o lote final, incluindo o SENDcomando , não é bloqueado pelo bloqueio Sch-M em espera.

O comportamento do bloqueio foi alterado no SQL 2012 ou 2014? Existe talvez alguma configuração de banco de dados ou servidor que possa afetar esse comportamento de bloqueio?

Joseph Daigle
fonte
Parece um possível bug. Você aplicou os SP e CUs mais recentes?
Max
1
@MaxVernon, estamos rodando 12.00.2370
Joseph Daigle
3
Você está usando o mesmo serviço que o iniciador e o destino. Os SENDblocos enquanto verifica a fila do iniciador . SENDnão bloquearia na fila de destino , simplesmente retornaria e seria usada sys.transmission_queuepara entrega. Se você separar os dois (sempre uma boa ideia), não terá o problema.
Remus Rusanu
1
Obrigado @RemusRusanu. Embora este exemplo seja parcialmente planejado para demonstrar o comportamento alterado, sua dica é uma que teremos em mente ao projetar nossos serviços e filas.
Joseph Daigle

Respostas:

17

O comportamento mudou entre o SQL Server 2008 R2 e o SQL Server 2012. A implementação do 2008 R2 era inconsistente com a semântica documentada 'FIFO relaxado' :

Os bloqueios são concedidos de maneira descontraída, primeiro a entrar, primeiro a sair (FIFO). Embora o pedido não seja estritamente FIFO, ele preserva propriedades desejáveis, como evitar a fome e trabalha para reduzir bloqueios e deadlocks desnecessários.

Novas solicitações de bloqueio em que o solicitante ainda não possui um bloqueio no recurso serão bloqueadas se o modo solicitado for incompatível com a união de pedidos concedidos e os modos de pedidos pendentes.

Uma solicitação de conversão será bloqueada apenas se o modo solicitado for incompatível com a união de todos os modos concedidos, excluindo o modo em que a própria solicitação de conversão foi originalmente concedida.

Em 2008 R2, uma nova Sch-Ssolicitação de bloqueio foi concedida, apesar de incompatível com a união de solicitações concedidas e em espera, o que pode levar à privação de bloqueio. Em 2012, a Sch-Ssolicitação de bloqueio é bloqueada.

O script de reprodução abaixo usa tabelas regulares em vez de uma fila do 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);

Em resumo, o 2008 R2 não se comportou como projetado. O problema foi corrigido no SQL Server 2012.

Paul White 9
fonte