Выполнение запроса отсюда, чтобы извлечь тупиковые события из сеанса расширенных событий по умолчанию
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
предложение, оно завершается менее чем за секунду, возвращая 3782 строки.
Точно так же, если я добавлю OPTION (MAXDOP 1)
к исходному запросу, который тоже ускоряет процесс, статистика теперь показывает значительно меньшее количество операций чтения лобов.
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
некоторой степени улучшает ситуацию (но это все еще занимает> 3 минуты), так как результаты DMV настолько малы, что я сомневаюсь, что сам тип 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
было 4 880 045 байт, и он содержал 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
где в любое время выделяется от 1800 до 3000 страниц.
WHERE
предложение в выражение XQuery; логика не должна быть удалена, чтобы все шло быстроTargetData.nodes ('RingBufferTarget[1]/event[@name = "xml_deadlock_report"]')
. Тем не менее, я недостаточно хорошо знаю внутренности XML, чтобы ответить на поставленный вами вопрос.