Jawaban dari @Kin, @AaronBertrand, dan @DBAFromTheCold sangat bagus dan sangat membantu. Salah satu info penting yang saya temukan selama pengujian yang jawaban lain ditinggalkan adalah bahwa Anda perlu menggunakan indeks yang dikembalikan dari sys.partitions
untuk diberikan HOBT_ID
ketika mencari %%lockres%%
(melalui petunjuk permintaan indeks). Indeks ini tidak selalu indeks PK atau berkerumun.
Sebagai contoh:
--Sometimes this does not return the correct results.
SELECT lockResKey = %%lockres%% ,*
FROM [MyDB].[dbo].[myTable]
WHERE %%lockres%% = @lockres
;
--But if you add the index query hint, it does return the correct results
SELECT lockResKey = %%lockres%% ,*
FROM [MyDB].[dbo].[myTable] WITH(NOLOCK INDEX([IX_MyTable_NonClustered_index]))
WHERE %%lockres%% = @lockres
;
Berikut ini contoh skrip yang dimodifikasi menggunakan potongan dari masing-masing jawaban ini.
declare @keyValue varchar(256);
SET @keyValue = 'KEY: 5:72057598157127680 (92d211c2a131)' --Output from deadlock graph: process-list/process[waitresource] -- CHANGE HERE !
------------------------------------------------------------------------
--Should not have to change anything below this line:
declare @lockres nvarchar(255), @hobbitID bigint, @dbid int, @databaseName sysname;
--.............................................
--PARSE @keyValue parts:
SELECT @dbid = LTRIM(SUBSTRING(@keyValue, CHARINDEX(':', @keyValue) + 1, CHARINDEX(':', @keyValue, CHARINDEX(':', @keyValue) + 1) - (CHARINDEX(':', @keyValue) + 1) ));
SELECT @hobbitID = convert(bigint, RTRIM(SUBSTRING(@keyValue, CHARINDEX(':', @keyValue, CHARINDEX(':', @keyValue) + 1) + 1, CHARINDEX('(', @keyValue) - CHARINDEX(':', @keyValue, CHARINDEX(':', @keyValue) + 1) - 1)));
SELECT @lockRes = RTRIM(SUBSTRING(@keyValue, CHARINDEX('(', @keyValue) + 0, CHARINDEX(')', @keyValue) - CHARINDEX('(', @keyValue) + 1));
--.............................................
--Validate DB name prior to running dynamic SQL
SELECT @databaseName = db_name(@dbid);
IF not exists(select * from sys.databases d where d.name = @databaseName)
BEGIN
RAISERROR(N'Database %s was not found.', 16, 1, @databaseName);
RETURN;
END
declare @objectName sysname, @indexName sysname, @schemaName sysname;
declare @ObjectLookupSQL as nvarchar(max) = '
SELECT @objectName = o.name, @indexName = i.name, @schemaName = OBJECT_SCHEMA_NAME(p.object_id, @dbid)
FROM ' + quotename(@databaseName) + '.sys.partitions p
JOIN ' + quotename(@databaseName) + '.sys.indexes i ON p.index_id = i.index_id AND p.[object_id] = i.[object_id]
JOIN ' + quotename(@databaseName)+ '.sys.objects o on o.object_id = i.object_id
WHERE hobt_id = @hobbitID'
;
--print @ObjectLookupSQL
--Get object and index names
exec sp_executesql @ObjectLookupSQL
,N'@dbid int, @hobbitID bigint, @objectName sysname OUTPUT, @indexName sysname OUTPUT, @schemaName sysname OUTPUT'
,@dbid = @dbid
,@hobbitID = @hobbitID
,@objectName = @objectName output
,@indexName = @indexName output
,@schemaName = @schemaName output
;
DECLARE @fullObjectName nvarchar(512) = quotename(@databaseName) + '.' + quotename(@schemaName) + '.' + quotename(@objectName);
SELECT fullObjectName = @fullObjectName, lockIndex = @indexName, lockRes_key = @lockres, hobt_id = @hobbitID, waitresource_keyValue = @keyValue;
--Validate object name prior to running dynamic SQL
IF OBJECT_iD( @fullObjectName) IS NULL
BEGIN
RAISERROR(N'The object "%s" was not found.',16,1,@fullObjectName);
RETURN;
END
--Get the row that was blocked
--NOTE: we use the NOLOCK hint to avoid locking the table when searching by %%lockres%%, which might generate table scans.
DECLARE @finalResult nvarchar(max) = N'SELECT lockResKey = %%lockres%% ,*
FROM ' + @fullObjectName
+ ISNULL(' WITH(NOLOCK INDEX(' + QUOTENAME(@indexName) + ')) ', '')
+ ' WHERE %%lockres%% = @lockres'
;
--print @finalresult
EXEC sp_executesql @finalResult, N'@lockres nvarchar(255)', @lockres = @lockres;
Anda memiliki hobt_id sehingga kueri berikut akan mengidentifikasi tabel: -
Dari itu Anda kemudian dapat menjalankan pernyataan berikut untuk mengidentifikasi baris dalam tabel (jika masih ada): -
Namun hati-hati dengan pernyataan di atas, itu akan memindai tabel target jadi jalankan di BACA TIDAK TERKESAN dan memantau server Anda.
Berikut ini artikel dari Grant Fritchey tentang %% LOCKRES %% - http://www.scarydba.com/2010/03/18/undocumented-virtual-column-lockres/
Dan inilah artikel dari blog saya sendiri tentang menggunakan %% LOCKRES %% untuk mengidentifikasi baris dari acara yang diperluas: - https://dbafromthecold.wordpress.com/2015/02/24/identifying-blocking-via-extended-events/
sumber
Ini adalah suplemen untuk jawaban yang sudah diposting oleh DBAFromTheCold dan Aaron Bertrand .
Microsoft masih meninggalkan
%%lockres%%
sebagai fitur tidak berdokumen .Di bawah ini adalah skrip yang akan membantu Anda :
Lihat juga posting blog yang luar biasa ini di: Kasus Penasaran tentang Kebuntuan yang Meragukan dan Kunci Tidak Begitu Logis
sumber
Maaf, sudah mengerjakan jawaban ini dan akan dikirim ketika yang lain muncul. Menambahkan sebagai komunitas wiki hanya karena pendekatannya sedikit berbeda dan menambahkan sedikit info lainnya.
Pada
543066506c7c
dasarnya hash kunci utama, dan Anda dapat mengambil baris itu (dan berpotensi setiap baris dengan tabrakan hash) menggunakan SQL dinamis ini:Anda dapat melakukan ini tanpa SQL dinamis, tentu saja, tetapi ini memberi Anda templat yang bagus untuk snippet atau prosedur tersimpan di mana Anda bisa mencolokkan nilainya, jika ini adalah sesuatu yang sering Anda atasi masalah. (Anda juga bisa parameterisasi nama tabel, dan Anda juga bisa membangun parsing dari KUNCI: string untuk menentukan semuanya untuk Anda secara dinamis, tapi saya pikir itu mungkin di luar jangkauan untuk posting ini.)
sumber