Ermitteln der gesperrten Tabelle oder Zeile in SQL Server


20

Ich versuche zu verstehen / zu lernen, wie man die Details einer blockierten Sitzung aufspürt.

Also habe ich folgendes Setup erstellt:

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

Jetzt verbinde ich mich zweimal von zwei verschiedenen Clients aus mit der Datenbank.

Die ersten Fragen der Sitzung:

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

Ich verpflichte mich dort ausdrücklich nicht , die Schlösser zu behalten.

In der zweiten Sitzung gebe ich die gleiche Aussage ab und natürlich, dass man wegen Sperrens wartet. Jetzt versuche ich, die verschiedenen Abfragen zu verwenden, um zu sehen, dass Sitzung 2 auf den fooTisch wartet .

sp_who2 Folgendes wird angezeigt (ich habe einige Spalten entfernt, um nur die wichtigen Informationen anzuzeigen):

SPID | Status | BlkBy | DBName | Befehl | SPID | ANFRAGE ID
----- + -------------- + ------- + ---------- + ---------- -------- + ------ + ----------
52 | schlafen | . | foodb | BEFEHL ERWARTEN | 52 | 0        
53 | schlafen | . | foodb | BEFEHL ERWARTEN | 53 | 0        
54 | AUSGEHÄNGT | 52 | foodb | UPDATE | 54 | 0        
56 | RUNNABLE | . | foodb | SELECT INTO | 56 | 0        

Dies wird erwartet, Sitzung 54 wird durch die nicht festgeschriebenen Änderungen von Sitzung 52 blockiert.

Das sys.dm_os_waiting_taskszeigt auch die Abfrage . Die Aussage:

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

kehrt zurück:

session_id | wait_type | resource_address | resource_description                                                            
----------- + ----------- + -------------------- + ----- -------------------------------------------------- --------------------------
        54 | LCK_M_X | 0x000000002a35cd40 | Tastensperre hobtid = 72057594046054400 dbid = 6 id = lock4ed1dd780 mode = X associatedObjectId = 72057594046054400

Auch dies wird erwartet.

Mein Problem ist, dass ich nicht herausfinden kann, wie ich den tatsächlichen Objektnamen finde, auf den Sitzung 54 wartet.

Ich habe mehrere Suchanfragen gefunden, die sich anschließen sys.dm_tran_locksund sys.dm_os_waiting_taskswie folgt lauten :

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

In meinem obigen Testszenario gibt dieser Join jedoch nichts zurück. Entweder ist dieser Join falsch oder dm_tran_locksenthält nicht die Informationen, nach denen ich suche.

Also, was ich suche, ist eine Abfrage, die so etwas wie zurückgibt:
" Sitzung 54 wartet auf eine Sperre in der Tabellefoo ".


Einige Hintergrundinformationen:

Das Problem im wirklichen Leben, das ich zu lösen versuche, ist etwas komplizierter, läuft aber auf die Frage hinaus, auf welchen Tisch Sitzung 54 wartet. Bei dem fraglichen Problem handelt es sich um eine umfangreiche gespeicherte Prozedur, die mehrere Tabellen aktualisiert und eine Auswahl aus einer Ansicht, die auf einige dieser Tabellen zugreift. Die selectAnweisung wird blockiert, obwohl die Snapshot-Isolierung und der Lese-Commit-Snapshot aktiviert sind. Der nächste Schritt besteht darin, herauszufinden, warum die Auswahl blockiert ist (was meiner Meinung nach nicht möglich wäre, wenn die Snapshot-Isolierung aktiviert ist).

Als ersten Schritt möchte ich herausfinden, worauf diese Sitzung wartet.



@MaxVernon: Danke, dass du das bestätigt hast. Aber dann bin ich noch verwirrter. Warum gibt es nichts zurück, obwohl ich weiß, dass es eine Sperre und eine blockierte Sitzung gibt?
a_horse_with_no_name

Ich kann das in SQL Server 2012 aufgetretene Problem nicht erneut erstellen. Ich habe eine Testdatenbank erstellt, RCSI aktiviert, Ihre Tabellen erstellt und beide Aktualisierungsanweisungen ausgeführt. Außerdem wird eine Zeile angezeigt, die von Ihrer letzten Abfrage zurückgegeben wurde.
Max Vernon

Wenn Sie eine visuelle Hilfe beim Erkennen Ihrer Sperren benötigen, steht Ihnen ein Open Source-Tool namens SQL Lock Finder zur Verfügung. Sie finden den Quellcode unter: github.com/LucBos/SqlLockFinder Oder laden Sie die ausführbare Datei unter: sqllockfinder.com herunter .
Luc Bos

Antworten:


23

Ich denke das macht was du brauchst.

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

Du kannst es versuchen :

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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.