Нещодавно ми перенесли виробничі екземпляри з 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
для доставки. Якщо ви розділите ці два (завжди хороша ідея), у вас не виникне проблеми.