Обнаружение заблокированной таблицы или строки в SQL Server

20

Я пытаюсь понять / научиться отслеживать детали заблокированного сеанса.

Поэтому я создал следующую настройку:

create table foo (id integer not null primary key, some_data varchar(20));
insert into foo values (1, 'foo');
commit;

Теперь я подключаюсь к базе данных дважды от двух разных клиентов.

Первая сессия вопросов:

begin transaction
update foo set some_data = 'update'
  where id = 1;

Я явно не совершаю там, чтобы сохранить замки.

Во втором сеансе я делаю то же самое заявление и, конечно, то, что каждый ждет из-за блокировки. Теперь я пытаюсь использовать различные запросы, чтобы увидеть, что сессия 2 ожидает fooтаблицы.

sp_who2 показывает следующее (я удалил некоторые столбцы, чтобы показать только важную информацию):

СПИД | Статус | BlkBy | DBName | Команда | СПИД | RequestID
----- + -------------- + ------- + ---------- + ---------- -------- + ------ + ----------
52 | спать | , | еда | ОЖИДАНИЕ КОМАНДЫ | 52 | 0        
53 | спать | , | еда | ОЖИДАНИЕ КОМАНДЫ | 53 | 0        
54 | ПОДВЕСНОЙ | 52 | еда | ОБНОВЛЕНИЕ | 54 | 0        
56 | RUNNABLE | , | еда | ВЫБРАТЬ В | 56 | 0        

Ожидается, что сеанс 54 заблокирован незафиксированными изменениями сеанса 52.

Запросы sys.dm_os_waiting_tasksтакже показывают это. Заявление:

select session_id, wait_type, resource_address, resource_description
from sys.dm_os_waiting_tasks
where blocking_session_id is not null;

возвращает:

session_id | wait_type | адрес_ресурса | resource_description                                                            
----------- + ----------- + -------------------- + ----- -------------------------------------------------- --------------------------
        54 | LCK_M_X | 0x000000002a35cd40 | keylock hobtid = 72057594046054400 dbid = 6 id = режим lock4ed1dd780 = X ассоциированныйObjectId = 72057594046054400

Опять же это ожидается.

Моя проблема в том, что я не могу понять, как найти фактическое имя объекта, которого ожидает сессия 54.

Я нашел несколько запросов, которые присоединяются sys.dm_tran_locksи sys.dm_os_waiting_tasksвот так:

SELECT ....
FROM sys.dm_tran_locks AS l
  JOIN sys.dm_os_waiting_tasks AS wt ON wt.resource_address = l.lock_owner_address

Но в моем приведенном выше тестовом сценарии это объединение ничего не возвращает. Так что либо это объединение неверно, либо на dm_tran_locksсамом деле не содержит информацию, которую я ищу.

Поэтому я ищу запрос, который возвращает что-то вроде:
« сеанс 54 ожидает блокировки в таблицеfoo ».


Некоторая справочная информация:

Реальная проблема, которую я пытаюсь решить, немного сложнее, но сводится к вопросу «на каком столе ожидает сессия 54». Проблема, о которой идет речь, включает в себя длинную хранимую процедуру, которая обновляет несколько таблиц, и выбор из представления, которое обращается к некоторым из этих таблиц. Оператор selectблокируется, даже если у нас есть изоляция моментального снимка и включенный моментальный снимок чтения. Выяснение, почему выбор заблокирован (что я думал, было бы невозможно, если включена изоляция моментального снимка) будет следующим шагом.

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

a_horse_with_no_name
источник
msdn.microsoft.com/en-us/library/ms190345.aspx говорит, что ваше присоединение правильное.
Макс Вернон,
@MaxVernon: спасибо, что подтвердил это. Но тогда я еще больше запутался. Почему он ничего не возвращает, хотя я знаю, что есть блокировка и заблокированный сеанс?
a_horse_with_no_name
Я не могу воссоздать проблему, с которой вы столкнулись в SQL Server 2012. Я создал тестовую базу данных, включил RCSI, создал ваши таблицы и выполнил оба оператора обновления, и я вижу строку, возвращенную вашим последним запросом.
Макс Вернон,
Если вам нужна визуальная помощь в обнаружении ваших блокировок, есть инструмент с открытым исходным кодом, который называется SQL Lock Finder. Вы можете найти источник по адресу : github.com/LucBos/SqlLockFinder или загрузить исполняемый файл по адресу: адресу sqllockfinder.com. Нам также нравится любой вклад, который вы могли бы внести в код, чтобы мы могли сделать его лучше.
Люк Бос

Ответы:

23

Я думаю, что это делает то, что вам нужно.

USE 'yourDB'
GO
SELECT  
    OBJECT_NAME(p.[object_id]) BlockedObject
FROM    sys.dm_exec_connections AS blocking
    INNER JOIN sys.dm_exec_requests blocked
        ON blocking.session_id = blocked.blocking_session_id
    INNER JOIN sys.dm_os_waiting_tasks waitstats
        ON waitstats.session_id = blocked.session_id
    INNER JOIN sys.partitions p ON SUBSTRING(resource_description, 
        PATINDEX('%associatedObjectId%', resource_description) + 19, 
        LEN(resource_description)) = p.partition_id
Джеймс Андерсон
источник
3

Можешь попробовать :

SELECT 
db_name(rsc_dbid) AS 'DATABASE_NAME',
case rsc_type when 1 then 'null'
              when 2 then 'DATABASE' 
              WHEN 3 THEN 'FILE'
              WHEN 4 THEN 'INDEX'
              WHEN 5 THEN 'TABLE'
              WHEN 6 THEN 'PAGE'
              WHEN 7 THEN 'KEY'
              WHEN 8 THEN 'EXTEND'
              WHEN 9 THEN 'RID ( ROW ID)'
              WHEN 10 THEN 'APPLICATION' end  AS 'REQUEST_TYPE',

CASE req_ownertype WHEN 1 THEN 'TRANSACTION'
                   WHEN 2 THEN 'CURSOR'
                   WHEN 3 THEN 'SESSION'
                   WHEN 4 THEN 'ExSESSION' END AS 'REQUEST_OWNERTYPE',

OBJECT_NAME(rsc_objid ,rsc_dbid) AS 'OBJECT_NAME', 
PROCESS.HOSTNAME , 
PROCESS.program_name , 
PROCESS.nt_domain , 
PROCESS.nt_username , 
PROCESS.program_name ,
SQLTEXT.text 
FROM sys.syslockinfo LOCK JOIN 
     sys.sysprocesses PROCESS
  ON LOCK.req_spid = PROCESS.spid
CROSS APPLY sys.dm_exec_sql_text(PROCESS.SQL_HANDLE) SQLTEXT
Амин Аттарзаде
источник