Визначення заблокованої таблиці або рядка в 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 показує наступне (я видалив кілька стовпців, щоб відобразити лише важливу інформацію):

SPID | Статус | BlkBy | DBName | Команда | SPID | ЗАПИТАННЯ
----- + -------------- + ------- + ---------- + ---------- -------- + ------ + ----------
52 | спить | . | foodb | ЗАЧЕКАЄМО КОМАНДА | 52 | 0        
53 | спить | . | foodb | ЗАЧЕКАЄМО КОМАНДА | 53 | 0        
54 | СУСПАННІ | 52 | foodb | ОНОВЛЕННЯ | 54 | 0        
56 | РАБОНА | . | foodb | ВИБІРТЬ У ВІД | 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 | address_address | 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блокується, навіть якщо у нас є ізоляція знімків та ввімкнено читання зроблених знімків. З'ясування, чому вибір заблокований (що, на мою думку, не вдасться, якщо включена ізоляція знімків), буде наступним кроком.

В якості першого кроку я хотів би дізнатися, на те , що очікує , що сесія.


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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.