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 WHERE
clá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 JOIN
melhorar 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 XML
foi 4,880,045 bytes e continha 1.448 eventos.) E teste de um corte a versão da consulta original com e sem a MAXDOP
dica.
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 616
pá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_usage
enquanto a consulta está em execução mostra que parece estar constantemente alocando e desalocando páginas tempdb
com algo entre 1.800 e 3.000 páginas alocadas ao mesmo tempo.
WHERE
clá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.