当我们通过下列SQL查询数据库当前正在执行的SQL时,我们会发现wait_resource时常会出现等待,今天就来对常见的等待对象类型进行介绍
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
SELECT
[session_id],
[request_id],
[start_time] AS '开始时间',
[status] AS '状态',
[command] AS '命令',
dest.[text] AS 'sql语句',
DB_NAME([database_id]) AS '数据库名',
[blocking_session_id] AS '正在阻塞其他会话的会话ID',
[wait_type] AS '等待资源类型',
[wait_time] AS '等待时间',
[wait_resource] AS '等待的资源',
[reads] AS '物理读次数',
[writes] AS '写次数',
[logical_reads] AS '逻辑读次数',
[row_count] AS '返回结果行数'
FROM sys.[dm_exec_requests] AS der
CROSS APPLY
sys.[dm_exec_sql_text](der.[sql_handle]) AS dest
ORDER BY [cpu_time] DESC
|
Page
对于page类型的等待,page字符往往会隐藏,其格式如下
1
|
waitresource="6:3:5335455" = Database_Id : FileId : PageNumber
|
通过DBCC PAGE查看对应页内容,必须开启3604 trace
1
2
|
DBCC TRACEON (3604);
DBCC PAGE (6,1,5335455,2);
|
其输出结果如下,其中Metadata: ObjectId为对应ID,我们可以通过select object_name(5335455)查看对应对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
PAGE: (1:5335455)
BUFFER:
BUF @0x0000000494C73840
bpage = 0x0000000C5BF28000 bhash = 0x0000000000000000 bpageno = (1:5335455)
bdbid = 6 breferences = 0 bcputicks = 0
bsampleCount = 0 bUse1 = 31633 bstat = 0x9
blog = 0x5215215a bnext = 0x0000000000000000
PAGE HEADER:
Page @0x0000000C5BF28000
m_pageId = (1:5335455) m_headerVersion = 1 m_type = 1
m_typeFlagBits = 0x0 m_level = 0 m_flagBits = 0x200
m_objId (AllocUnitId.idObj) = 105172m_indexId (AllocUnitId.idInd) = 256
Metadata: AllocUnitId = 72057600930480128
Metadata: PartitionId = 72057600417857536 Metadata: IndexId = 1
Metadata: ObjectId = 498868894 m_prevPage = (1:5335454) m_nextPage = (1:5335800)
pminlen = 48 m_slotCnt = 49 m_freeCnt = 3980
m_freeData = 7968 m_reservedCnt = 0 m_lsn = (1172491:239610:691)
m_xactReserved = 0 m_xdesId = (1:861477284) m_ghostRecCnt = 0
m_tornBits = 352880690 DB Frag ID = 1
Allocation Status
GAM (1:5112320) = ALLOCATED SGAM (1:5112321) = NOT ALLOCATED
PFS (1:5329992) = 0x40 ALLOCATED 0_PCT_FULL DIFF (1:5112326) = NOT CHANGED
ML (1:5112327) = NOT MIN_LOGGED
|
根据DBCC PAGE返回的内容,可以使用 %%physloc%% 来查看Page上数据行的定位器。在Page上,每一个数据行都可以通过一个索引来寻址,该索引就是数据行的定位器
1
2
3
4
5
|
SELECT
sys.fn_PhysLocFormatter (%%physloc%%) AS PhysLoc,
*
FROM [table_name] WITH(NOLOCK)
WHERE sys.fn_PhysLocFormatter (%%physloc%%) like '(1:5335455%'
|
key
对于等待的资源是Key的情况,该阻塞发生在聚集索引上,Key资源的格式是 database_id, hobt_id (Magic Hash),其中 Magic Hash的某一个数据行的哈希值
1
|
waitresource=“KEY: 6:72057594041991168 (ce52f92a058c)” = Database_Id, HOBT_Id ( Magic Hash )
|
定位等待的对象
1
2
|
select * from sys.partitions where hobt_id=72057600638910464
select object_name([object_id])
|
定位具体的行
1
2
3
|
SELECT *
FROM [table_name] WITH(NOLOCK)
WHERE %%lockres%% = '(ce52f92a058c)';
|
RID
对于等待资源是RID的情况,阻塞发生在heap上,也就是说,RID等待只会发生在没有创建聚集索引的表上
1
|
waitresource="RID: 6:15:11695844:3"= Databae_Id:File_Id:Page_Id:Slot_No
|
该描述符表示等待的资源某一个特定的行,数据行存储在Page上,Page的底部是行偏移(Row Offsets),每一行的偏移量连续排列在Page的末尾,称作槽数组(Slot Array),每一个slot中存储的都是行在Page中的偏移量
OBJECT和TABLE
1
|
waitresource="OBJECT: 6:12347015633:1 "=Database_Id:Object_Id:PageNumber
|
我们可以通过PageNumber来还原阻塞发生的情况
1
|
waitresource="TAB: 5:261575970:1"=DatabaseID:ObjectID:IndexID
|
阻塞过程中,由于全表扫描导致整张表都锁定了
Tips
https://www.cnblogs.com/ljhdo/p/10533774.html
https://support.microsoft.com/zh-cn/help/4460004/how-to-resolve-last-page-insert-pagelatch-ex-contention-in-sql-server