আমি কীভাবে একটি এসকিউএল সার্ভারের ডেডলক রিপোর্টে একটি কীকে মানকে রূপান্তর করতে পারি?


15

আমার একটি অচল প্রতিবেদন আছে যা আমাকে বলে যে ওয়েটারসোর্স জড়িত একটি বিরোধ ছিল = "কেই: 9: 72057632651542528 (543066506c7c)" এবং আমি এটি দেখতে পারি:

<keylock hobtid="72057632651542528" dbid="9" objectname="MyDatabase.MySchema.MyTable" indexname="MyPrimaryKeyIndex" id="locka8c6f4100" mode="X" associatedObjectId="72057632651542528">

<রিসোর্স-লিস্ট> এর মধ্যে। আমি কীটির প্রকৃত মানটি সন্ধান করতে সক্ষম হতে চাই (উদাহরণস্বরূপ ID = 12345)। তথ্যটি পেতে আমার কী এসকিউএল বিবৃতি ব্যবহার করতে হবে?

উত্তর:


9

@ কিন, @ অ্যারোনবার্ট্র্যান্ড এবং @ ডিবিএফ্রোম দ্য কোল্ডের উত্তরগুলি দুর্দান্ত এবং খুব সহায়ক ছিল। পরীক্ষাগুলির সময় আমি যে তথ্যগুলির একটি গুরুত্বপূর্ণ অংশ খুঁজে পেয়েছি তা অন্য উত্তরগুলি বাদ পড়ে তা হ'ল আপনাকে যখন সূচীটি (ইনডেক্স ক্যোয়ারী ইঙ্গিতের মাধ্যমে) সন্ধানের সময় sys.partitionsদেওয়া হয় HOBT_IDতখন ফিরে আসে %%lockres%%। এই সূচকটি সর্বদা পিকে বা ক্লাস্টারড সূচক হয় না।

উদাহরণ স্বরূপ:

--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
;

এই উত্তরগুলির প্রতিটি থেকে টুকরো ব্যবহার করে এখানে একটি উদাহরণ স্ক্রিপ্ট পরিবর্তন করা হয়েছে।

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;

ডাটাবেসের নাম স্বয়ংক্রিয়ভাবে নির্ধারণ করা সূচি ইঙ্গিত সহ এখানে একটি দুর্দান্ত মান-যুক্ত। ধন্যবাদ!
মার্ক ফ্রিম্যান 14

14

আপনার কাছে hobt_id রয়েছে তাই নিম্নলিখিত কোয়েরিটি সারণীটি সনাক্ত করবে: -

SELECT o.name
FROM sys.partitions p
INNER JOIN sys.objects o ON p.object_id = o.object_id
WHERE p.hobt_id = 72057632651542528

সেখান থেকে আপনি সারণীতে সারিটি সনাক্ত করতে নিম্নলিখিত বিবৃতিটি চালাতে পারেন (এটি এখনও বিদ্যমান থাকলে): -

SELECT %%LOCKRES%%,  *
FROM [TABLE NAME] WITH(INDEX(MyPrimaryKeyIndex))
WHERE %%LOCKRES%% = '(543066506c7c)'

উপরের বিবৃতিটি সম্পর্কে সতর্ক থাকুন তবে এটি লক্ষ্যযুক্ত টেবিলটি স্ক্যান করবে যাতে চালনা না করে চালিত হয় এবং আপনার সার্ভারটি পর্যবেক্ষণ করে।

এখানে গ্রান্ট ফ্রিটচির একটি নিবন্ধ এখানে প্রায়%% LOCKRES %% - http://www.scarydba.com/2010/03/18/undocumented-virtual-column-lockres/

এবং একটি বর্ধিত ইভেন্ট থেকে সারিগুলি সনাক্ত করতে %% LOCKRES %% ব্যবহার সম্পর্কে আমার নিজের ব্লগের একটি নিবন্ধ এখানে রয়েছে: - https://dbafromthecold.wordpress.com/2015/02/24/hdfying-blocking-via-extended-events/


দ্রুত প্রতিক্রিয়া এবং সহায়ক ব্লগ পোস্টগুলির লিঙ্ক অন্তর্ভুক্ত করার জন্য ধন্যবাদ।
মার্ক ফ্রিম্যান

9

এটি ইতিমধ্যে ডিবিএফরোমডকোল্ড এবং অ্যারন বার্ট্র্যান্ড পোস্ট করা উত্তরের পরিপূরক ।

মাইক্রোসফ্ট এখনও %%lockres%%অননুমোদিত বৈশিষ্ট্য হিসাবে রেখে গেছে ।

নীচে স্ক্রিপ্ট যা আপনাকে সাহায্য করবে :

declare @databaseName varchar(100) = 'yourdatabaseName' --CHANGE HERE !
declare @keyValue varchar(100) = 'KEY: 9:72057632651542528 (543066506c7c)' --Output from deadlock graph -- CHANGE HERE !
declare @lockres varchar(100)
declare @hobbitID bigint

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) + 1, CHARINDEX(')', @keyValue) - CHARINDEX('(', @keyValue) - 1))

declare @objectName sysname
declare @ObjectLookupSQL as nvarchar(max) = '
SELECT @objectName = o.name
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 = ' + convert(nvarchar(50), @hobbitID) + ''

--print @ObjectLookupSQL
exec sp_executesql @ObjectLookupSQL
    ,N'@objectName sysname OUTPUT'
    ,@objectName = @objectName output

--print @objectName

declare @finalResult nvarchar(max) = N'select %%lockres%% ,* 
from ' + quotename(@databaseName) + '.dbo.' + @objectName + '
where %%lockres%% = ''(' + @lockRes + ')''
'
--print @finalresult
exec sp_executesql @finalResult

এছাড়াও এই দুর্দান্ত ব্লগ পোস্টটি দেখুন: দুবাইস ডেডলকের কৌতূহলী কেস এবং নট সো লজিক্যাল লক


আমি উত্তর হিসাবে এটি বাছাই করছি। যদিও ডিবিএফ্রোম দ্য কোল্ড এবং অ্যারন বার্ট্র্যান্ড উভয়ই প্রদত্ত সমাধানগুলি কাজ করে, এটি আমার জন্য কেবল কেইওয়াই সরবরাহ করে তথ্য পেতে সক্ষম করে (যদিও ডেটাবেজে কিছু অতিরিক্ত বোঝা থাকলে আমার কাছে ইতিমধ্যে রয়েছে এমন তথ্য প্রাপ্ত করার জন্য, তবে বরং একসাথে সরবরাহ না)।
মার্ক ফ্রিম্যান

আত্মীয়, আমি মনে করি আপনি এখানে অনেক দূর এসেছেন, এবং আমি আপনার উত্তরগুলি আরও বেশি সময় মুগ্ধ হয়ে যাই। তবে অন্য কারও দ্বারা লিখিত কোড প্রস্তাব করার সময় আপনার উত্স (গুলি) প্রকাশ করা উচিত (অভিন্ন কোডটি এখানে , এখানে এবং এখানে )।
অ্যারন বারট্র্যান্ড

@ অ্যারনবার্ট্র্যান্ড আমার এই কোডটি দীর্ঘকাল ধরে ছিল এবং আমার কোনও রেফারেন্স নেই, যেহেতু আমি এটি ব্যবহার করছি। আপনি রেফারেন্সটি নির্দেশ করার পরে আপনাকে ধন্যবাদ (আমি এটি আমার ভাণ্ডারেও যুক্ত করব)। এছাড়াও, ভাল শব্দ জন্য ধন্যবাদ! আমাকে সম্প্রদায়কে শিখতে ও ফিরিয়ে দিতে অনেক দীর্ঘ পথ যেতে হবে। ক্ষমা চেয়ে নিলাম এবং আমি সত্যিকার অর্থে রেফারেন্সটি উদ্ধৃত করার অর্থ নয়
কিন শাহ

6

দুঃখিত, ইতিমধ্যে এই উত্তরে এবং অন্য প্রকাশিত হওয়ার পরে পোস্ট করার বিষয়ে কাজ করেছিল। সম্প্রদায়ের উইকি হিসাবে যুক্ত করা কেবল কারণ এটি কিছুটা ভিন্ন পদ্ধতির এবং কিছুটা অন্যান্য তথ্য যোগ করে।

543066506c7cমূলত প্রাথমিক কী একটি হ্যাশ, এবং আপনি (এবং একটি হ্যাশ সংঘর্ষের সঙ্গে সম্ভাব্য কোনো সারি) যে সারি উদ্ধার করতে পারেন এই গতিশীল এসকিউএল ব্যবহার করছে:

-- Given: KEY: 9:72057632651542528 (543066506c7c)
-- and object = MyDatabase.MySchema.MyTable

DECLARE 
  @hobt BIGINT = 72057632651542528,
  @db SYSNAME = DB_NAME(9),
  @res VARCHAR(255) = '(543066506c7c)';

DECLARE @exec NVARCHAR(MAX) = QUOTENAME(@db) + N'.sys.sp_executesql';

DECLARE @sql NVARCHAR(MAX) = N'SELECT %%LOCKRES%%,*
  FROM MySchema.MyTable WHERE %%LOCKRES%% = @res;';

EXEC @exec @sql, N'@res VARCHAR(255)', @res;

আপনি অবশ্যই গতিশীল এসকিউএল ছাড়াই এটি করতে পারেন, তবে এটি আপনাকে একটি স্নিপেট বা সঞ্চিত পদ্ধতির জন্য একটি দুর্দান্ত টেম্পলেট দেয় যেখানে আপনি কেবল মানগুলি প্লাগ করতে পারেন, যদি আপনি খুব সমস্যা সমাধান করেন এমন কিছু হয়। (আপনি টেবিলের নামটিও প্যারামিটারাইজ করতে পারেন, এবং আপনি কেইওয়াইয়ের পার্সিংয়ের ক্ষেত্রেও তৈরি করতে পারেন: আপনার জন্য সমস্ত কিছু গতিশীলভাবে নির্ধারণ করার জন্য স্ট্রিং, তবে আমি ভেবেছিলাম যে এটি এই পোস্টের সুযোগের বাইরে নয়))

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.