Executando a consulta daqui para extrair os eventos de deadlock da sessão de eventos estendidos padrão
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';
demora cerca de 20 minutos a concluir na minha máquina. As estatísticas relatadas são
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.
Se eu remover a WHEREcláusula, ela será concluída em menos de um segundo, retornando 3.782 linhas.
Da mesma forma, se eu adicionar OPTION (MAXDOP 1)à consulta original que também acelera as coisas, as estatísticas agora mostram muito menos leituras de 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.
Então minha pergunta é
Alguém pode explicar o que está acontecendo? Por que o plano original é tão catastroficamente pior e existe alguma maneira confiável de evitar o problema?
Adição:
Também descobri que alterar a consulta para INNER HASH JOINmelhorar as coisas até certo ponto (mas ainda leva mais de 3 minutos), pois os resultados do DMV são tão pequenos que duvido que o tipo Join seja o responsável, e presumo que algo mais deva ter mudado. Estatísticas para isso
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.
Depois de encher o tampão anel eventos alargados DATALENGTH(da XMLfoi 4,880,045 bytes e continha 1.448 eventos.) E teste de um corte a versão da consulta original com e sem a MAXDOPdica.
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
Deu os seguintes resultados
+-------------------------------------+------+----------+
| | 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 |
+-------------------------------------+------+----------+
Há uma clara diferença nas alocações tempdb, sendo que a mais rápida mostra as 616páginas que foram alocadas e desalocadas. Essa é a mesma quantidade de páginas usadas quando o XML também é colocado em uma variável.
Para o plano lento, essas contagens de alocação de páginas estão na casa dos milhões. A pesquisa dm_db_task_space_usageenquanto a consulta está em execução mostra que parece estar constantemente alocando e desalocando páginas tempdbcom algo entre 1.800 e 3.000 páginas alocadas ao mesmo tempo.












WHEREcláusula para a expressão XQuery; a lógica não tem que ser removido para que ele vá rápido:TargetData.nodes ('RingBufferTarget[1]/event[@name = "xml_deadlock_report"]'). Dito isto, não conheço elementos internos XML suficientemente bem para responder à pergunta que você fez.