Mendeteksi tabel atau baris yang terkunci di SQL Server

20

Saya mencoba memahami / mempelajari cara melacak detail sesi yang diblokir.

Jadi saya membuat pengaturan berikut:

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

Sekarang saya terhubung ke database dua kali dari dua klien yang berbeda.

Masalah sesi pertama:

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

Saya secara eksplisit tidak berkomitmen di sana untuk menjaga kunci.

Pada sesi kedua saya mengeluarkan pernyataan yang sama dan tentu saja orang menunggu karena penguncian. Sekarang saya mencoba menggunakan kueri yang berbeda untuk melihat bahwa sesi 2 sedang menunggu footabel.

sp_who2 menunjukkan yang berikut (Saya menghapus beberapa kolom untuk hanya menampilkan informasi penting):

SPID | Status | BlkBy | DBName | Command | SPID | PERMINTAAN
----- + -------------- + ------- + ---------- + ---------- -------- + ------ + ----------
52 | tidur | . | makanan | PERINTAH AWAITING | 52 | 0        
53 | tidur | . | makanan | PERINTAH AWAITING | 53 | 0        
54 | DITANGGUHKAN | 52 | makanan | PEMBARUAN | 54 | 0        
56 | DIMINTA | . | makanan | PILIH KE DALAM | 56 | 0        

Ini diharapkan, sesi 54 diblokir oleh perubahan yang tidak dilakukan dari sesi 52.

Pertanyaan sys.dm_os_waiting_tasksjuga menunjukkan ini. Pernyataan:

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

pengembalian:

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

Sekali lagi ini diharapkan.

Masalah saya adalah, saya tidak tahu bagaimana menemukan nama objek aktual yang ditunggu sesi 54.

Saya telah menemukan beberapa pertanyaan yang bergabung sys.dm_tran_locksdan sys.dm_os_waiting_tasksseperti ini:

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

Tetapi dalam skenario pengujian saya di atas bergabung ini tidak menghasilkan apa-apa. Jadi salah satu yang bergabung itu salah atau dm_tran_lockstidak benar-benar mengandung informasi yang saya cari.

Jadi yang saya cari adalah kueri yang mengembalikan sesuatu seperti:
" sesi 54 sedang menunggu kunci dalam tabelfoo ".


Beberapa info latar belakang:

Masalah kehidupan nyata yang saya coba selesaikan sedikit lebih rumit, tetapi bermuara pada pertanyaan "pada tabel mana sesi 54 menunggu". Masalah yang dipermasalahkan melibatkan prosedur tersimpan berukuran besar yang memperbarui beberapa tabel dan memilih dari tampilan yang mengakses beberapa tabel tersebut. The selectpernyataan diblokir meskipun kita memiliki snapshot isolasi dan membaca berkomitmen snapshot diaktifkan. Mencari tahu mengapa pilih diblokir (yang saya pikir tidak akan mungkin jika isolasi snapshot diaktifkan) akan menjadi langkah berikutnya.

Sebagai langkah pertama saya ingin mencari tahu tentang apa yang menunggu sesi itu.

seekor kuda tanpa nama
sumber
msdn.microsoft.com/en-us/library/ms190345.aspx mengatakan gabung Anda benar.
Max Vernon
@ MaxVernon: terima kasih sudah mengkonfirmasi itu. Tapi kemudian saya bahkan lebih bingung. Mengapa tidak mengembalikan apa pun walaupun saya tahu ada kunci dan sesi diblokir?
a_horse_with_no_name
Saya tidak dapat membuat kembali masalah yang Anda lihat di SQL Server 2012. Saya membuat database pengujian, mengaktifkan RCSI, membuat tabel Anda, dan menjalankan kedua pernyataan pembaruan, dan saya melihat baris yang dikembalikan oleh permintaan terakhir Anda.
Max Vernon
Jika Anda ingin alat bantu visual dalam mendeteksi kunci Anda ada alat open source yang tersedia yang disebut SQL lock finder. Anda dapat menemukan sumbernya di: github.com/LucBos/SqlLockFinder Atau unduh yang dapat dieksekusi di: sqllockfinder.com Kami juga menyukai kontribusi apa pun yang dapat Anda berikan pada kode sehingga kami dapat membuatnya lebih baik.
Luc Bos

Jawaban:

23

Saya pikir ini melakukan apa yang Anda butuhkan.

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
sumber
3

Kamu bisa mencobanya :

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
sumber