Понекогаш ќе има повеќе информации во џиновскиот XML што го проучувате (графиците за ќор-сокак содржат листа на ресурси што ви помагаат да ги дознаете имињата на објектите и индексите), но не секогаш.
Овој текст ќе ви помогне да ги дешифрирате.
Сите информации што се тука се на Интернет на разни места, само се многу дистрибуирани! Сакам да составам сè заедно - од DBCC PAGE до hobt_id и до недокументираните функции %%physloc%% и %%lockres%%.
Прво, ајде да зборуваме за чекањата на заклучувањата на СТРАНИЦА, а потоа ќе преминеме на заклучувањата KEY.
1) waitresource=„СТРАНИЦА: 6:3:70133“ = Ид_база на податоци: ИД на датотека: Број на страница
Ако вашето барање чека на заклучување на СТРАНИЦА, SQL Server ќе ви ја даде адресата на таа страница.
Разложувајќи ја „СТРАНИЦА: 6:3:70133“ добиваме:
ID_база на податоци = 6
data_file_id = 3
број_страница = 70133
1.1) Декриптирај database_id
Ајде да го најдеме името на базата на податоци користејќи го барањето:
SELECT
name
FROM sys.databases
WHERE database_id=6;
GO
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 и знаменцето за трага 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.
Скоро готово! Сега можете да ги најдете имињата на табелите и индексите користејќи го барањето:
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
И сега гледаме дека чекањето за заклучување беше на индексот PK_Sales_OrderLines на табелата Sales.OrderLines.
Забелешка: Во SQL Server 2014 и подоцна, името на објектот може да се најде и со помош на недокументираните DMO sys.dm_db_database_page_allocations. Но, мора да ја прашате секоја страница во базата на податоци, што не изгледа многу кул за големи бази на податоци, па затоа користев DBCC PAGE.
1.4) Дали е можно да се видат податоците на страницата што е блокирана?
Па, да. Но... дали сте сигурни дека навистина ви треба?
Бавно е дури и на мали маси. Но, некако е кул, затоа што сте прочитале до сега... ајде да зборуваме за %%physloc%%!
Сега кога знаеме дека сакаме да ја заклучиме страницата во 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 редови за кои се бореше нашето барање
Доста е за заклучувањата на СТРАНИЦА. Што ако чекаме заклучување KEY?
2) waitresource=„КЛУЧ: 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
Во контекст на пронајдената база на податоци, треба да извршите барање за 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
Ми кажува дека барањето чекало на заклучувањето на Application.Countries користејќи го индексот PK_Application_Countries.
2.3) Сега малку магија %%lockres%% - ако сакате да дознаете кој запис е заклучен
Ако навистина сакам да знам на кој ред беше вклучена бравата, можам да дознаам со пребарување на самата табела. Можеме да ја користиме недокументираната функција %%lockres%% за да најдеме запис што одговара на магичниот хаш.
Ве молиме имајте предвид дека ова барање ќе ја скенира целата табела, а на големите маси ова можеби не е воопшто забавно:
SELECT
*
FROM Application.Countries (NOLOCK)
WHERE %%lockres%% = '(ce52f92a058c)';
GO
Додадов NOLOCK (по совет на Клаус Ашенбренер на Твитер) бидејќи блокадите можат да станат проблем. Ние само сакаме да погледнеме што има сега, а не што беше таму кога започна трансакцијата - мислам дека не ни е важна конзистентноста на податоците.
Voila, рекордот за кој се боревме!
Признанија и понатамошно читање
Не се сеќавам кој прв опиша многу од овие работи, но еве два поста за најмалку документирани работи што можеби ќе ви се допаднат: