Commit 8a8becc
Attribute check_id 9 blocking wait time to the chain's lead blocker
The "Top Blocking Query" rollup previously summed each BPR's victim
wait_time against the direct blocker's sql_handle. In a chain like
A blocks B blocks C, B would show up as a blocker "responsible" for C's
wait — but B was itself stuck behind A, so blaming B is misleading.
The only query that needs tuning is A.
This commit rewrites the rollup so every BPR's victim wait cascades up
to the chain's lead blocker (level-0 session in the monitor_loop):
- New #session_leads temp table materializes a (monitor_loop, lead_desc,
session_desc) map via a recursive CTE. Anchor rows are lead blockers
(sessions that never appear as a blocked_desc in the same
monitor_loop); recursion walks downstream, keeping lead_desc constant
so every descendant inherits the same root.
- Cycle guard mirrors the existing hierarchy CTE pattern (lead_path
LIKE check, MAXRECURSION 100).
- Fallback pass inserts any blocking_desc not reached by the recursion
as its own lead — catches true cycle cases (mutual blocking before
deadlock detection fires) so their waits don't silently drop.
- bpr_with_lead CTE joins #blocking to #session_leads on session_desc
to find each BPR's chain lead, extracts victim waittime from the
blocked-process/@WaitTime XPath (the correct "how long did the victim
wait" value), and applies the @database_name / @object_name filters
at the BPR level rather than the chain level so we can still trace
waits that cascade across objects.
- lead_sql CTE pulls a representative sql_handle / stmtstart / stmtend /
query_text_pre per (monitor_loop, lead_desc) from any #blocking row
where the lead appears as the blocking-process.
- per_victim CTE dedupes to (lead_sql_identity, victim_tx) with peak
wait, matching the existing dedup pattern across repeat BPR fires.
- Final INSERT groups by (database_name, lead_sql_handle, stmtstart,
stmtend), keeps the existing "must be >= 10% of total" HAVING filter,
and renames finding_group to 'Top Lead Blocker'. The finding text now
reads 'This lead blocker accounted for ... across N blocked sessions
in its chain.' to make the cascaded-attribution semantic explicit.
Intermediate blockers (sessions that blocked downstream but were
themselves victims) no longer appear in the rollup — by design. Their
apparent blocking time cascaded up to whoever's actually holding the
lock at the top of the chain.
Smoke-tested on sql2022 against real hammerdb_tpcc BPR data: the
#session_leads debug dump shows correct (monitor_loop, lead, session)
mappings for chains of depth 2-4, and the rollup surfaces three
neword/delivery procs that together account for 100% of chain wait
time (43.3% + 30.2% + 26.5%). Previously intermediate blockers that
clogged this list no longer appear. Also compiled cleanly on sql2017
as a syntax sanity check.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent a08cdb3 commit 8a8becc
1 file changed
Lines changed: 258 additions & 63 deletions
0 commit comments