SQL Server'da kilitli tabloyu veya satırı algılama


20

Engellenen bir oturumun ayrıntılarını nasıl izleyeceğimizi anlamaya / öğrenmeye çalışıyorum.

Bu yüzden aşağıdaki kurulumu oluşturdum:

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

Şimdi veritabanına iki farklı istemciden iki kez bağlanıyorum.

İlk oturum:

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

Ben açıkça do not kilitleri tutmak için orada işlemek.

İkinci seansta aynı ifadeyi veriyorum ve elbette ki kilitlenmeyi beklemektedir. Şimdi oturum 2 footabloyu bekliyor görmek için etrafında yüzen farklı sorguları kullanmaya çalışıyorum .

sp_who2 aşağıdakileri gösterir (yalnızca önemli bilgileri göstermek için bazı sütunları kaldırdım):

SPID | Durum | BlkBy | DBName | Komut | SPID | RequestID
----- + -------------- + ------- + ---------- + ---------- -------- + ------ + ----------
52 | uyku | . | foodb | BEKLENEN KOMUT | 52 | 0        
53 | uyku | . | foodb | BEKLENEN KOMUT | 53 | 0        
54 | ASMA | 52 | foodb | GÜNCELLEME | 54 | 0        
56 | ÇALIŞABİLİR | . | foodb | SEÇİNİZ | 56 | 0        

Bu beklenir, oturum 54, oturum 52'deki taahhüt edilmemiş değişiklikler nedeniyle engellenir.

Sorgulama bunu sys.dm_os_waiting_tasksda gösterir. İfade:

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

İadeler:

oturum_kimliği | wait_type | kaynak_adresi | resource_description                                                            
----------- + ----------- + -------------------- + ----- -------------------------------------------------- --------------------------
        54 | LCK_M_X | 0x000000002a35cd40 | keylock hobtid = 72057594046054400 dbid = 6 id = lock4ed1dd780 modu = X ilişkiliObjectId = 72057594046054400

Yine bu bekleniyor.

Benim sorunum, oturum 54 beklediği gerçek nesne adını bulmak nasıl anlayamıyorum olmasıdır.

Ben katılmadan sys.dm_tran_locksve bunun sys.dm_os_waiting_tasksgibi birkaç sorgu bulduk :

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

Ancak yukarıdaki test senaryomda bu birleştirme bir şey döndürmüyor. Yani ya birleştirme yanlış ya dm_tran_locksda aslında aradığım bilgiyi içermiyor.

Ben ne aradığım gibi bir şey döndüren bir sorgu:
" oturum 54 tabloda bir kilit bekliyorfoo ".


Bazı arka plan bilgileri:

Çözmeye çalıştığım gerçek sorun biraz daha karmaşık, ama "hangi tabloda oturum 54 bekliyor" sorusuna kayıyor. Söz konusu sorun, birkaç tabloyu güncelleyen büyük bir saklı yordam ve bu tabloların bazılarına erişen bir görünümden seçim içerir. selectDeyim biz anlık yalıtım ve taahhüt anlık etkin okumamıza rağmen engellenir. Seçimin neden engellendiğini (anlık görüntü yalıtımı etkinleştirilirse mümkün olmadığını düşündüm) bulmak bir sonraki adım olacaktır.

İlk adım olarak, o oturumun ne beklediğini öğrenmek istiyorum .



@ MaxVernon: bunu onayladığınız için teşekkürler. Ama sonra kafam daha da karıştı. Ben her ne kadar Neden hiçbir şey dönmez biliyorum bir kilit ve engellenen bir oturum var mı?
a_horse_with_no_name

SQL Server 2012'de gördüğünüz sorunu yeniden oluşturamıyorum. Bir test veritabanı oluşturdum, RCSI'yı etkinleştirdim, tablolarınızı oluşturdum ve her iki güncelleme deyimini de çalıştırdım ve son sorgunuz tarafından döndürülen bir satır görüyorum.
Max Vernon

Kilitlerinizi tespit etmek için görsel bir yardım istiyorsanız, SQL kilit bulucu adı verilen açık kaynaklı bir araç vardır. Kaynağı şu adreste bulabilirsiniz: github.com/LucBos/SqlLockFinder Veya şu yürütülebilir dosyayı indirebilirsiniz: sqllockfinder.com Ayrıca kodu daha iyi yapabilmemiz için yapabileceğiniz tüm katkıları da seviyoruz.
Luc Bos

Yanıtlar:


23

Bence bu ihtiyacınız olanı yapıyor.

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

Deneyebilirsin :

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.