Rilevamento della tabella o della riga bloccate in SQL Server


20

Sto cercando di capire / imparare a rintracciare i dettagli di una sessione bloccata.

Quindi ho creato la seguente configurazione:

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

Ora mi collego al database due volte da due client diversi.

I primi numeri della sessione:

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

Non mi impegno esplicitamente lì per mantenere i blocchi.

Nella seconda sessione rilascio la stessa dichiarazione e, naturalmente, si attende a causa del blocco. Ora sto cercando di utilizzare le diverse query fluttuanti per vedere che la sessione 2 è in attesa del footavolo.

sp_who2 mostra quanto segue (ho rimosso alcune colonne per mostrare solo le informazioni importanti):

SPID | Stato | BlkBy | DBName | Comando | SPID | IDRichiesta
----- + -------------- + ------- + ---------- + ---------- -------- + ------ + ----------
52 | dormire | . | foodb | COMANDO IN ATTESA | 52 | 0        
53 | dormire | . | foodb | COMANDO IN ATTESA | 53 | 0        
54 | SOSPESO | 52 | foodb | AGGIORNAMENTO | 54 | 0        
56 | FUNZIONABILE | . | foodb | SELEZIONA IN | 56 | 0        

Ciò è previsto, la sessione 54 è bloccata dalle modifiche non impegnate dalla sessione 52.

Anche le query sys.dm_os_waiting_tasksmostrano questo. La dichiarazione:

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

ritorna:

session_id | wait_type | indirizzo_risorse | resource_description                                                            
----------- + ----------- + -------------------- + ----- -------------------------------------------------- --------------------------
        54 | LCK_M_X | 0x000000002a35cd40 | keylock hobtid = 72057594046054400 dbid = 6 id = lock4ed1dd780 mode = X associateObjectId = 72057594046054400

Anche questo è previsto.

Il mio problema è che non riesco a capire come trovare il nome effettivo dell'oggetto che la sessione 54 sta aspettando.

Ho trovato diverse query che si stanno unendo sys.dm_tran_lockse in sys.dm_os_waiting_tasksquesto modo:

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

Ma nel mio scenario di test sopra questo join non restituisce nulla. Quindi o quel join è sbagliato o in dm_tran_locksrealtà non contiene le informazioni che sto cercando.

Quindi quello che sto cercando è una query che restituisca qualcosa del tipo:
"la sessione 54 è in attesa di un blocco nella tabellafoo ".


Alcune informazioni di base:

Il problema della vita reale che sto cercando di risolvere è un po 'più complicato, ma si riduce alla domanda "su quale tavolo è in attesa la sessione 54". Il problema in questione riguarda una procedura memorizzata di grandi dimensioni che aggiorna diverse tabelle e una selezione da una vista che accede ad alcune di quelle tabelle. L' selectistruzione è bloccata anche se abbiamo l'isolamento dello snapshot e la lettura dello snapshot di commit è abilitata. Capire perché la selezione è bloccata (cosa che pensavo non sarebbe possibile se fosse abilitato l'isolamento dello snapshot) sarà il prossimo passo.

Come primo passo vorrei scoprire cosa sta aspettando quella sessione.


msdn.microsoft.com/en-us/library/ms190345.aspx afferma che il tuo join è corretto.
Max Vernon,

@MaxVernon: grazie per averlo confermato. Ma poi sono ancora più confuso. Perché non restituisce nulla anche se so che c'è un blocco e una sessione bloccata?
a_horse_with_no_name

Non riesco a ricreare il problema riscontrato in SQL Server 2012. Ho creato un database di prova, abilitato RCSI, creato le tabelle ed eseguito entrambe le istruzioni di aggiornamento e vedo una riga restituita dall'ultima query.
Max Vernon,

Se si desidera un aiuto visivo nel rilevamento dei blocchi, è disponibile uno strumento open source chiamato Finder di blocchi SQL. Puoi trovare la fonte su: github.com/LucBos/SqlLockFinder O scaricare l'eseguibile su: sqllockfinder.com Adoriamo anche tutti i contributi che potresti dare al codice in modo da poterlo migliorare.
Luc Bos,

Risposte:


23

Penso che questo faccia quello che ti serve.

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

Puoi provarlo :

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.