Нещодавно ми перенесли виробничі екземпляри з SQL 2008 R2 на абсолютно нові сервери SQL 2014. Ось цікавий сценарій, який ми розкрили за допомогою сервісного брокера. Розглянемо базу даних 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;
Ключовим тут є те, що ми повертаємо транзакцію п'ять разів . Це запускає вбудовану фонову логіку Poison Message Handling . Хоча чергу не відключається (оскільки вона налаштована не відключати), фонове завдання все ще намагається виконати роботу та запустити 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 році? Чи може бути якийсь параметр бази даних або сервера, який може вплинути на цю поведінку блокування?
SENDблоки при перевірці ініціатора черзі. SENDне блокується на цільовій черзі, вона просто відскакує та використає sys.transmission_queueдля доставки. Якщо ви розділите ці два (завжди хороша ідея), у вас не виникне проблеми.