Как отслеживать блокировки, которые происходят менее чем за секунду - SQL Server

14

Я пытаюсь устранить проблему с блокировкой, которая происходит менее секунды. Приложение OLTP очень чувствительно и должно иметь время отклика менее 200 мс для некоторых транзакций в соответствии с согласованным SLA. У нас были проблемы с эскалацией блокировки в новом выпуске кода, которые мы смогли решить, уменьшив размер пакета в обновлениях. Мы подозреваем, что даже при небольшом размере пакета новый sp блокирует те же строки, которые обновляет транзакция OLTP.

Мне нужно найти сеанс, который блокируется, и ресурс, на котором он находится. Насколько я понимаю, «порог заблокированного процесса» может быть установлен как минимум на 1 секунду, поэтому блокировка не будет зафиксирована.

Я экспериментирую с событиями wait_info и wait_completed x.

Есть ли другой способ, которым мы могли бы это отследить. Благодарность

jesijesi
источник
тот же вопрос, что и от того же пользователя: stackoverflow.com/questions/38407021/…
TheGameiswar

Ответы:

10

Поскольку вас особенно интересует блокировка, а не общие ожидания, locks_lock_waitsрасширенное событие звучит более подходящим.

С фильтром на increment >= 200

CREATE EVENT SESSION [locks_lock_waits] ON SERVER 
ADD EVENT sqlserver.locks_lock_waits(
        ACTION(sqlserver.sql_text)
            WHERE  ( [sqlserver].[is_system] = 0
                     AND [increment] >= 200
                     AND [counter] <= 1000 ) 
    )
ADD TARGET package0.ring_buffer;

GO

ALTER EVENT SESSION [locks_lock_waits]  
ON SERVER  STATE = start;  

Выше собраны операторы, ожидающие блокировки в течение порогового количества времени, но не дают конкретного ресурса блокировки.

Я никогда не использовал это событие и не понимаю, какие издержки может вызвать эта сессия на вашем производственном сервере.

Я нашел это видео по теме. Это настоятельно рекомендует фильтрацию наcounter чтобы уменьшить количество собранных событий, и я сделал это выше.

Также упоминается старая устаревшая недокументированная команда

dbcc lock(StallReportThreshold, 200) -- 200 is threshold in ms

Который (если флаг трассировки 3605 включен) сбрасывает ограниченную информацию, такую ​​как ниже, в журнал ошибок SQL Server.

Процесс 53 ожидал 6844 мс для блокировки S на RID: 2: 1: 120: 2 результат: OKWAIT

Я просто упомянул об этом мимоходом, поскольку расширенные события были бы явно предпочтительнее в любом случае, поскольку они задокументированы и намного более эффективны.

Мартин Смит
источник
Я протестировал locks_lock_waits, и, как вы сказали, у него нет информации о ресурсе. Но я не знал, что прирост был временем. Хорошая информация dbcc lock, отлично выглядит. Вы знаете, как долго эта информация доступна, прежде чем она может быть сброшена в журнал ошибок.
jesijesi
Извините, я не прояснил себя. Я спрашивал, сколько у нас времени, пока мы не запустим команду блокировки dbcc. Например, происходит блокировка, и если я запускаю dbcc lock через час, мы все еще получаем информацию?
jesijesi
@jesijesi - я никогда не слышал об этом до сегодняшнего дня. У меня нет больше информации об этом. Я даже не знаю, какие параметры нужно передать, чтобы отключить его. Но вы запускаете dbcc lock(StallReportThreshold, 200) сначала, и он выводит информацию, как только пороговое значение превышено, если включен флаг трассировки 3605. SQL Server не собирает эту информацию на случай, если вы сможете запустить ее позже.
Мартин Смит
2
Благодарю. просто добавив ссылку, которая имеет полезную функцию для преобразования значений resource_0,1,2 в xevents. sqlnotes.info/2011/10/24/…
jesijesi
5

Если вы заинтересованы в блокировке, доступно несколько расширенных событий:

lock_acquired
lock_released
lock_escalation

Первые два события имеют duration столбец в (микросекунды), который вы можете отфильтровать по вашим порогам. У них также есть resource_descriptionдействие, которое даст вам некоторую информацию о задействованных ресурсах.

В lock_escalationсобытии также есть statementдействие, которое вы можете добавить, чтобы собрать инструкцию T-SQL, которая вызвала эскалацию блокировки. Это также имеет escalation_cause. Вот пример сеанса:

CREATE EVENT SESSION [locking] ON SERVER 
ADD EVENT sqlserver.lock_acquired( SET collect_resource_description = (1) ),
ADD EVENT sqlserver.lock_escalation( SET collect_statement = (1) ),
ADD EVENT sqlserver.lock_released( SET collect_resource_description = (1) )
WITH (MAX_MEMORY=4096 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=30 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=NONE,TRACK_CAUSALITY=OFF,STARTUP_STATE=OFF)
GO

Я подозреваю, что, возможно, есть причина, по которой вы не можете установить порог отчета о заблокированном процессе менее чем на секунду: блокировка совершенно нормальна в СУБД - ядро ​​базы данных должно блокировать ресурсы для их защиты. Хотя нет официального определения того, когда блокировка становится блокировкой, блокировка, тикающая в течение секунды, кажется для меня нормальным явлением.

wBob
источник
1
блокировка становится блокирующей, как только кому-то другому отказывают в доступе к ресурсу, и он вынужден ждать из-за блокировки.
Мартин Смит
Спасибо, я планирую использовать lock_acquired с полем продолжительности.
jesijesi
Удачи. Поскольку вы работаете на SQL Server 2014, вы можете использовать таблицы OLTP в памяти с встроенными скомпилированными хранимыми процессами, предлагая высокую производительность без защелок. Вы также можете посмотреть на изоляцию снимка.
wBob