SELECT CAST (
REPLACE (
REPLACE (
XEventData.XEvent.value ('(data/value)[1]', 'varchar(max)'),
'<victim-list>', '<deadlock><victim-list>'),
'<process-list>', '</victim-list><process-list>')
AS XML) AS DeadlockGraph
FROM (SELECT CAST (target_data AS XML) AS TargetData
FROM sys.dm_xe_session_targets st
JOIN sys.dm_xe_sessions s ON s.address = st.event_session_address
WHERE [name] = 'system_health') AS Data
CROSS APPLY TargetData.nodes ('//RingBufferTarget/event') AS XEventData (XEvent)
WHERE XEventData.XEvent.value('@name', 'varchar(4000)') = 'xml_deadlock_report';
在我的计算机上完成大约需要20分钟。报告的统计数据是
Table 'Worktable'. Scan count 0, logical reads 68121, physical reads 0, read-ahead reads 0,
lob logical reads 25674576, lob physical reads 0, lob read-ahead reads 4332386.
SQL Server Execution Times:
CPU time = 1241269 ms, elapsed time = 1244082 ms.
如果删除该WHERE
子句,它会在不到一秒的时间内完成返回3,782行。
类似地,如果我添加OPTION (MAXDOP 1)
到原始查询中,它也加快了速度,现在的统计信息显示大量的lob读取减少。
Table 'Worktable'. Scan count 0, logical reads 15, physical reads 0, read-ahead reads 0,
lob logical reads 6767, lob physical reads 0, lob read-ahead reads 6076.
SQL Server Execution Times:
CPU time = 639 ms, elapsed time = 693 ms.
所以我的问题是
谁能解释这是怎么回事?为什么原始计划如此灾难性地恶化,并且有任何可靠的方法来避免该问题?
加成:
我还发现,INNER HASH JOIN
由于DMV结果太小,更改查询以在某种程度上改善了情况(但是仍然需要3分钟以上),因此我怀疑Join类型本身是负责任的,并且认为必须进行其他更改。统计数据
Table 'Worktable'. Scan count 0, logical reads 30294, physical reads 0, read-ahead reads 0,
lob logical reads 10741863, lob physical reads 0, lob read-ahead reads 4361042.
SQL Server Execution Times:
CPU time = 200914 ms, elapsed time = 203614 ms.
填补了扩展事件环缓冲区(以后DATALENGTH
的XML
是4880045个字节,它包含了1448点的事件。)和测试的切口向下原始查询的版本有和没有MAXDOP
暗示。
SELECT COUNT(*)
FROM (SELECT CAST (target_data AS XML) AS TargetData
FROM sys.dm_xe_session_targets st
JOIN sys.dm_xe_sessions s
ON s.address = st.event_session_address
WHERE [name] = 'system_health') AS Data
CROSS APPLY TargetData.nodes ('//RingBufferTarget/event') AS XEventData (XEvent)
WHERE XEventData.XEvent.value('@name', 'varchar(4000)') = 'xml_deadlock_report'
SELECT*
FROM sys.dm_db_task_space_usage
WHERE session_id = @@SPID
得到以下结果
+-------------------------------------+------+----------+
| | Fast | Slow |
+-------------------------------------+------+----------+
| internal_objects_alloc_page_count | 616 | 1761272 |
| internal_objects_dealloc_page_count | 616 | 1761272 |
| elapsed time (ms) | 428 | 398481 |
| lob logical reads | 8390 | 12784196 |
+-------------------------------------+------+----------+
tempdb分配有明显的不同,显示616
页面已分配和释放的速度更快。这与将XML放入变量时使用的页面数量相同。
对于慢速计划,这些页面分配数将达到数百万。dm_db_task_space_usage
查询运行时进行轮询表明,它似乎一直在不断分配和取消分配页面,tempdb
其中任意一次分配了1,800到3,000个页面。
WHERE
子句移到XQuery表达式中。无需删除逻辑即可使其快速运行:TargetData.nodes ('RingBufferTarget[1]/event[@name = "xml_deadlock_report"]')
。也就是说,我对XML的内部知识还不够了解,无法回答您提出的问题。