Giải mã khóa và trang WaitResource trong bế tắc và khóa

Nếu bạn sử dụng báo cáo quy trình bị chặn hoặc thu thập biểu đồ bế tắc do SQL Server cung cấp định kỳ, bạn sẽ gặp phải những vấn đề như sau:

waitresource="TRANG: 6:3:70133"

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

Đôi khi sẽ có nhiều thông tin hơn trong XML khổng lồ mà bạn đang nghiên cứu (biểu đồ bế tắc chứa danh sách các tài nguyên giúp bạn tìm ra tên đối tượng và chỉ mục), nhưng không phải lúc nào cũng vậy.

Văn bản này sẽ giúp bạn giải mã chúng.

Tất cả thông tin ở đây đều có trên Internet ở nhiều nơi khác nhau, nó được phân phối rất rộng rãi! Tôi muốn kết hợp mọi thứ lại với nhau - từ TRANG DBCC đến hobt_id và đến các hàm %%physloc%% và %%lockres%% không có giấy tờ.

Trước tiên, hãy nói về việc chờ đợi đối với khóa TRANG, sau đó chúng ta sẽ chuyển sang khóa KEY.

1) waitresource=“TRANG: 6:3:70133” = Cơ sở dữ liệu_Id: FileId: Số trang

Nếu truy vấn của bạn đang chờ khóa TRANG, SQL Server sẽ cung cấp cho bạn địa chỉ của trang đó.

Chia nhỏ “TRANG: 6:3:70133” chúng tôi nhận được:

  • cơ sở dữ liệu_id = 6
  • dữ liệu_file_id = 3
  • số_trang = 70133

1.1) Giải mã cơ sở dữ liệu_id

Hãy tìm tên cơ sở dữ liệu bằng truy vấn:

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

Đây là công khai Nhà nhập khẩu DB WideWorld trên máy chủ SQL của tôi.

1.2) Tìm kiếm tên file dữ liệu - nếu bạn quan tâm

Chúng ta sẽ sử dụng data_file_id trong bước tiếp theo để tìm tên bảng. Bạn có thể chỉ cần chuyển sang bước tiếp theo, nhưng nếu quan tâm đến tên tệp, bạn có thể tìm thấy nó bằng cách chạy truy vấn trong ngữ cảnh của cơ sở dữ liệu được tìm thấy, thay thế data_file_id trong truy vấn này:

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

Trong cơ sở dữ liệu WideWorldImporters, đây là một tệp có tên WWI_UserData và tôi đã khôi phục nó vào C:MSSQLDATAWideWorldImporters_UserData.ndf. (Rất tiếc, bạn đã bắt gặp tôi đang đưa các tập tin vào đĩa hệ thống! Không! Điều đó thật khó xử).

1.3) Lấy tên đối tượng từ TRANG DBCC

Bây giờ chúng ta biết rằng trang #70133 trong tệp dữ liệu 3 thuộc về cơ sở dữ liệu WorldWideImporters. Chúng ta có thể xem nội dung của trang này bằng TRANG DBCC không có giấy tờ và cờ theo dõi 3604.
Lưu ý: Tôi thích sử dụng TRANG DBCC trên bản sao được khôi phục từ bản sao lưu ở đâu đó trên máy chủ khác, vì đó là một thứ không có giấy tờ. Trong một số trường hợp, cô ấy có thể dẫn đến một bãi chứa được tạo ra (khoảng người dịch - thật không may, liên kết không dẫn đến đâu cả, nhưng xét theo url, chúng ta đang nói về các chỉ mục được lọc).

/* 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

Cuộn qua các kết quả, bạn có thể tìm thấy object_id và index_id.
Giải mã khóa và trang WaitResource trong bế tắc và khóa
Sắp xong! Bây giờ bạn có thể tìm thấy tên bảng và chỉ mục bằng truy vấn:

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

Và bây giờ chúng ta thấy rằng thời gian chờ khóa nằm trên chỉ mục PK_Sales_OrderLines của bảng Sales.OrderLines.

Lưu ý: Trong SQL Server 2014 trở lên, bạn cũng có thể tìm thấy tên đối tượng bằng cách sử dụng DMO sys.dm_db_database_page_allocations không có giấy tờ. Nhưng bạn phải truy vấn mọi trang trong cơ sở dữ liệu, điều này trông không bắt mắt lắm đối với cơ sở dữ liệu lớn, vì vậy tôi đã sử dụng TRANG DBCC.

1.4) Có thể xem dữ liệu trên trang bị chặn không?

Vâng, vâng. Nhưng... bạn có chắc là mình thực sự cần nó không?
Nó chậm ngay cả trên các bàn nhỏ. Nhưng nó khá thú vị, vì vậy vì bạn đã đọc đến đây... hãy nói về %%physloc%%!

%%physloc%% là một phép thuật không có giấy tờ sẽ trả về mã nhận dạng vật lý cho mỗi mục nhập. bạn có thể dùng %%physloc%% cùng với sys.fn_PhysLocFormatter trong SQL Server 2008 trở lên.

Bây giờ chúng ta biết rằng mình muốn khóa trang trong Sales.OrderLines, chúng ta có thể xem tất cả dữ liệu trong bảng này, được lưu trữ trong tệp dữ liệu số 3 trên trang #70133, bằng cách sử dụng truy vấn này:

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

Như tôi đã nói, nó chậm ngay cả trên những chiếc bàn nhỏ. Tôi đã thêm NOLOCK vào yêu cầu vì chúng tôi vẫn không đảm bảo rằng dữ liệu chúng tôi muốn xem giống hệt như dữ liệu khi phát hiện khóa - vì vậy chúng tôi có thể thực hiện các thao tác đọc sai một cách an toàn.
Nhưng, hoan hô, truy vấn trả về cho tôi 25 hàng giống như truy vấn của chúng tôi đã đấu tranh
Giải mã khóa và trang WaitResource trong bế tắc và khóa
Đủ về khóa TRANG. Điều gì sẽ xảy ra nếu chúng ta đang chờ khóa KEY?

2) waitresource=“KEY: 6:72057594041991168 (ce52f92a058c)” = Database_Id, HOBT_Id (băm ma thuật có thể được giải mã bằng %%lockres%% nếu bạn thực sự muốn điều đó)

Nếu truy vấn của bạn cố khóa một bản ghi trong chỉ mục và tự khóa bản ghi đó thì bạn sẽ nhận được một loại địa chỉ hoàn toàn khác.
Chia “6:72057594041991168 (ce52f92a058c)” thành nhiều phần, chúng ta có:

  • cơ sở dữ liệu_id = 6
  • hobt_id = 72057594041991168
  • hàm băm ma thuật = (ce52f92a058c)

2.1) Giải mã cơ sở dữ liệu_id

Điều này hoạt động chính xác giống như ví dụ trên! Tìm tên cơ sở dữ liệu bằng truy vấn:

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

Trong trường hợp của tôi nó vẫn như vậy Nhà nhập khẩu DB WideWorld.

2.2) Giải mã hobt_id

Trong ngữ cảnh của cơ sở dữ liệu được tìm thấy, bạn cần thực hiện truy vấn tới sys.partitions bằng một cặp liên kết sẽ giúp xác định tên của bảng và chỉ mục...

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

Nó cho tôi biết rằng yêu cầu đang chờ trên khóa Application.Countries bằng chỉ mục PK_Application_Countries.

2.3) Bây giờ có một chút phép thuật %%lockres%% - nếu bạn muốn tìm ra mục nào đã bị khóa

Nếu tôi thực sự muốn biết khóa ở hàng nào, tôi có thể tìm hiểu bằng cách truy vấn chính bảng đó. Chúng ta có thể sử dụng hàm %%lockres%% không có giấy tờ để tìm mục nhập khớp với hàm băm ma thuật.
Xin lưu ý rằng truy vấn này sẽ quét toàn bộ bảng và trên các bảng lớn, điều này có thể không thú vị chút nào:

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

Tôi đã thêm NOLOCK (theo lời khuyên của Klaus Aschenbrenner trên Twitter) vì tắc nghẽn có thể trở thành một vấn đề. Chúng tôi chỉ muốn xem những gì hiện có chứ không phải những gì đã có khi giao dịch bắt đầu - Tôi không nghĩ rằng tính nhất quán của dữ liệu là quan trọng đối với chúng tôi.
Thì đấy, kỷ lục mà chúng ta đã đấu tranh để giành được!
Giải mã khóa và trang WaitResource trong bế tắc và khóa

Lời cảm ơn và đọc thêm

Tôi không nhớ ai là người đầu tiên mô tả những điều này, nhưng đây là hai bài viết về những điều ít được ghi chép nhất mà bạn có thể thích:

Nguồn: www.habr.com

Thêm một lời nhận xét