死鎖和鎖中的Decipher Key和Page WaitResource

如果你定期使用阻塞進程報告或者收集SQL Server提供的死鎖圖,你會遇到這樣的事情:

waitresource =“頁面:6:3:70133”

waitresource=“KEY: 6:72057594041991168 (ce52f92a058c)“

有時,您研究的那個巨大的 XML 中會有更多信息(死鎖圖包含幫助您找出對象和索引名稱的資源列表),但並非總是如此。

本文將幫助您破譯它們。

這裡的所有信息都在互聯網上的各個地方,簡直太分散了! 我想把它們放在一起,從 DBCC PAGE 到 hobt_id 再到未記錄的 %%physloc%% 和 %%lockres%% 函數。

首先,讓我們談談等待 PAGE 鎖,然後再談談 KEY 鎖。

1) waitresource="PAGE: 6:3:70133" = Database_Id: FileId: PageNumber

如果您的請求正在等待 PAGE 鎖,SQL Server 將為您提供該頁面的地址。

分解“PAGE:6:3:70133”我們得到:

  • 數據庫 ID = 6
  • 數據文件 ID = 3
  • page_number = 70133

1.1) 解密database_id

使用查詢查找數據庫的名稱:

SELECT 
    name 
FROM sys.databases 
WHERE database_id=6;
GO

這是公開的 DB WideWorld進口商 在我的 SQL Server 上。

1.2) 尋找數據文件的名稱——如果你感興趣的話

我們將在下一步中使用 data_file_id 來查找表名。 您可以直接跳到下一步,但如果您對文件名感興趣,可以通過在找到的數據庫的上下文中運行查詢來找到它,將 data_file_id 替換到該查詢中:

USE WideWorldImporters;
GO
SELECT 
    name, 
    physical_name
FROM sys.database_files
WHERE file_id = 3;
GO

在 WideWorldImporters 數據庫中,這是一個名為 WWI_UserData 的文件,我已將其恢復到 C:MSSQLDATAWideWorldImporters_UserData.ndf。 (糟糕,你發現我把文件放在系統驅動器上了!不!這很尷尬)。

1.3) 從 DBCC PAGE 獲取對象名稱

我們現在知道數據文件 70133 中的頁面 #3 屬於 WorldWideImporters 數據庫。 我們可以使用未記錄的 DBCC PAGE 和跟踪標誌 3604 查看此頁面的內容。
注意:我更喜歡在另一台服務器上某處的恢復副本上使用 DBCC PAGE,因為它是未記錄的東西。 在某些情況下,她 可能導致轉儲 (約翻譯器 - 不幸的是,該鏈接無處可去,但從 url 來看,我們正在談論過濾索引).

/* This trace flag makes DBCC PAGE output go to our Messages tab
instead of the SQL Server Error Log file */
DBCC TRACEON (3604);
GO
/* DBCC PAGE (DatabaseName, FileNumber, PageNumber, DumpStyle)*/
DBCC PAGE ('WideWorldImporters',3,70133,2);
GO

通過滾動到結果,您可以找到 object_id 和 index_id。
死鎖和鎖中的Decipher Key和Page WaitResource
快完成了! 現在您可以通過查詢找到表名和索引名:

USE WideWorldImporters;
GO
SELECT 
    sc.name as schema_name, 
    so.name as object_name, 
    si.name as index_name
FROM sys.objects as so 
JOIN sys.indexes as si on 
    so.object_id=si.object_id
JOIN sys.schemas AS sc on 
    so.schema_id=sc.schema_id
WHERE 
    so.object_id = 94623380
    and si.index_id = 1;
GO

在這裡我們看到等待鎖是在 Sales.OrderLines 表的 PK_Sales_OrderLines 索引上。

注意:在 SQL Server 2014 及更高版本中,也可以使用未記錄的 DMO sys.dm_db_database_page_allocations 找到對象名稱。 但是你必須查詢數據庫中的每一頁,這對於大型數據庫來說看起來不太酷,所以我使用了 DBCC PAGE。

1.4) 是否可以看到被屏蔽頁面的數據?

嗚嗚,是的。 但是……你確定你真的需要它嗎?
即使在小桌子上也很慢。 但這有點酷,所以既然你已經讀到這裡了……讓我們談談 %%physloc%%!

%%physloc%% 是一個未記錄的魔術片段,它返回每個條目的物理 ID。 您可以使用 %%physloc%% 以及 SQL Server 2008 及更高版本中的 sys.fn_PhysLocFormatter.

現在我們知道我們想要在 Sales.OrderLines 中屏蔽該頁面,我們可以查看此表中的所有數據,該表存儲在頁面 #3 的數據文件 #70133 中,查詢如下:

Use WideWorldImporters;
GO
SELECT 
    sys.fn_PhysLocFormatter (%%physloc%%),
    *
FROM Sales.OrderLines (NOLOCK)
WHERE sys.fn_PhysLocFormatter (%%physloc%%) like '(3:70133%'
GO

正如我所說,即使在小桌子上它也很慢。 我在請求中添加了 NOLOCK,因為我們仍然不能保證我們要查看的數據與發現鎖時的數據完全相同——因此我們可以安全地進行臟讀。
但是,萬歲,查詢返回了我們的查詢所針對的 25 行。
死鎖和鎖中的Decipher Key和Page WaitResource
關於 PAGE 鎖的內容已經足夠了。 如果我們正在等待 KEY 鎖怎麼辦?

2) waitresource="KEY: 6:72057594041991168 (ce52f92a058c)" = Database_Id, HOBT_Id(如果你真的想的話,可以用%%lockres%%解密的魔法哈希)

如果您的查詢試圖鎖定索引條目並自己被鎖定,您將獲得完全不同類型的地址。
將“6:72057594041991168 (ce52f92a058c)”分成幾部分,我們得到:

  • 數據庫 ID = 6
  • hobt_id = 72057594041991168
  • 魔法散列 = (ce52f92a058c)

2.1) 解密database_id

這與上面的例子完全一樣! 使用查詢查找數據庫名稱:

SELECT 
    name 
FROM sys.databases 
WHERE database_id=6;
GO

就我而言,它是一樣的 DB WideWorld進口商.

2.2) 解密hobt_id

在找到的數據庫的上下文中,您需要使用幾個有助於確定表和索引名稱的連接來查詢 sys.partitions ...

USE WideWorldImporters;
GO
SELECT 
    sc.name as schema_name, 
    so.name as object_name, 
    si.name as index_name
FROM sys.partitions AS p
JOIN sys.objects as so on 
    p.object_id=so.object_id
JOIN sys.indexes as si on 
    p.index_id=si.index_id and 
    p.object_id=si.object_id
JOIN sys.schemas AS sc on 
    so.schema_id=sc.schema_id
WHERE hobt_id = 72057594041991168;
GO

它告訴我請求正在使用 PK_Application_Countries 索引等待 Application.Countries 鎖。

2.3) 現在來一些 %%lockres%% 魔術——如果你想找出哪個條目被鎖定

如果我真的想知道哪一行需要鎖,我可以通過查詢表本身來找到。 我們可以使用未記錄的 %%lockres%% 函數來查找與魔術哈希匹配的條目。
請注意,此查詢將掃描整個表,並且在大表上這可能一點也不有趣:

SELECT
    *
FROM Application.Countries (NOLOCK)
WHERE %%lockres%% = '(ce52f92a058c)';
GO

我添加了 NOLOCK (根據 Klaus Aschenbrenner 在推特上的建議) 因為鎖可能是個問題。 我們只想看看現在有什麼,而不是交易開始時有什麼——我認為數據一致性對我們來說並不重要。
瞧,我們為之奮鬥的記錄!
死鎖和鎖中的Decipher Key和Page WaitResource

致謝和進一步閱讀

我不記得是誰首先描述了其中的許多內容,但這裡有兩篇關於您可能喜歡的記錄最少的內容的帖子:

來源: www.habr.com

添加評論