Détection de la table ou de la ligne verrouillée dans SQL Server

20

J'essaie de comprendre / apprendre à retrouver les détails d'une session bloquée.

J'ai donc créé la configuration suivante:

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

Maintenant, je me connecte deux fois à la base de données à partir de deux clients différents.

La première session émet:

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

Je ne m'engage pas explicitement là-bas afin de garder les verrous.

Dans la deuxième session, j'émets la même déclaration et bien sûr que l'on attend en raison du verrouillage. Maintenant, j'essaie d'utiliser les différentes requêtes flottantes pour voir que la session 2 attend la footable.

sp_who2 affiche ce qui suit (j'ai supprimé certaines colonnes pour n'afficher que les informations importantes):

SPID | Statut | BlkBy | DBName | Commande | SPID | DEMANDÉ
----- + -------------- + ------- + ---------- + ---------- -------- + ------ + ----------
52 | dormir | . | foodb | EN ATTENTE DE COMMANDE | 52 | 0        
53 | dormir | . | foodb | EN ATTENTE DE COMMANDE | 53 | 0        
54 | SUSPENDU | 52 | foodb | MISE À JOUR | 54 | 0        
56 | RUNNABLE | . | foodb | SÉLECTIONNEZ DANS | 56 | 0        

Cela est attendu, la session 54 est bloquée par les modifications non validées de la session 52.

L'interrogation le sys.dm_os_waiting_tasksmontre également. La déclaration:

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

Retour:

session_id | wait_type | adresse_ressource | description_ressource                                                            
----------- + ----------- + -------------------- + ----- -------------------------------------------------- --------------------------
        54 | LCK_M_X | 0x000000002a35cd40 | hobtid de verrouillage = 72057594046054400 dbid = 6 id = mode lock4ed1dd780 = X associatedObjectId = 72057594046054400

Encore une fois, cela est attendu.

Mon problème est que je ne peux pas trouver comment trouver le nom d'objet réel que la session 54 attend.

J'ai trouvé plusieurs requêtes qui se joignent sys.dm_tran_lockset sys.dm_os_waiting_taskscomme ceci:

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

Mais dans mon scénario de test ci-dessus, cette jointure ne renvoie rien. Donc, cette jointure est incorrecte ou dm_tran_locksne contient pas réellement les informations que je recherche.

Donc, ce que je recherche, c'est une requête qui renvoie quelque chose comme:
"la session 54 attend un verrou dans la tablefoo ".


Quelques informations de fond:

Le vrai problème que j'essaie de résoudre est un peu plus compliqué, mais se résume à la question "sur quelle table la session 54 attend-elle". Le problème en question implique une procédure stockée de grande taille qui met à jour plusieurs tables et une sélection dans une vue qui accède à certaines de ces tables. L' selectinstruction est bloquée même si l'isolement de l'instantané et la lecture de l'instantané validé sont activés. Déterminer pourquoi la sélection est bloquée (ce que je pensais ne serait pas possible si l'isolement de l'instantané est activé) sera la prochaine étape.

Dans un premier temps, j'aimerais savoir ce que cette session attend.

un cheval sans nom
la source
msdn.microsoft.com/en-us/library/ms190345.aspx indique que votre jointure est correcte.
Max Vernon
@MaxVernon: merci de l'avoir confirmé. Mais je suis encore plus confus. Pourquoi ne retourne-t-il rien alors que je sais qu'il y a un verrou et une session bloquée?
a_horse_with_no_name
Je ne parviens pas à recréer le problème que vous voyez dans SQL Server 2012. J'ai créé une base de données de test, activé RCSI, créé vos tables et exécuté les deux instructions de mise à jour, et je vois une ligne renvoyée par votre dernière requête.
Max Vernon
Si vous voulez une aide visuelle pour détecter vos verrous, il existe un outil open source appelé SQL lock finder. Vous pouvez trouver la source sur: github.com/LucBos/SqlLockFinder Ou télécharger l'exécutable sur: sqllockfinder.com Nous aimons également toutes les contributions que vous pourriez apporter au code afin que nous puissions l'améliorer.
Luc Bos

Réponses:

23

Je pense que cela fait ce dont vous avez besoin.

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
James Anderson
la source
3

Tu peux l'essayer :

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
Amin Attarzadeh
la source