Add typed blocker-side columns to blocking_BlockedProcessReport#996
Merged
Merged
Conversation
Move blocked-process-report XML parsing from analysis time to collection time on the SQL side. Five new columns on collect.blocking_BlockedProcessReport (blocking_spid, blocking_last_tran_started, blocking_status, blocked_sql_text, blocking_sql_text) are populated at insert time inside collect.process_blocked_process_xml via XQuery against the stored <event>-rooted XML using the descendant axis. A 2.11.0 -> 2.12.0 upgrade script adds the columns idempotently and backfills existing activity='blocked' rows in a single pass. Idempotency on backfill and live UPDATE is via WHERE blocking_spid IS NULL. Defense-in-depth: if sp_HumanEventsBlockViewer writes rows but the XQuery extraction populates zero typed columns, a TYPED_COLUMNS_EMPTY row is written to config.collection_log so any future wire-format regression is visible without waiting for the analysis path to surface garbage chains. This is the schema-only PR. The Dashboard C# read-path simplification (deleting BlockedProcessXmlParser.cs and switching SqlServerFactCollector / SqlServerDrillDownCollector to read the new columns directly) ships in a follow-up PR. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 26, 2026
erikdarlingdata
added a commit
that referenced
this pull request
May 27, 2026
MisterZeus
pushed a commit
to MisterZeus/PerformanceMonitor
that referenced
this pull request
Jun 5, 2026
…r blocking reports
MisterZeus
pushed a commit
to MisterZeus/PerformanceMonitor
that referenced
this pull request
Jun 5, 2026
The Dashboard fact collector and drill-down collector now read the typed blocker-side columns added in erikdarlingdata#996 (blocking_spid, blocking_last_tran_started, blocking_status, blocked_sql_text, blocking_sql_text) directly from collect.blocking_BlockedProcessReport instead of re-parsing blocked_process_report_xml on every analysis cycle — up to 5000 XElement.Parse calls per BLOCKING_CHAIN fact collection are eliminated. BlockedProcessXmlParser is deleted; no callers remain. Lite is unchanged — it has no SQL-side staging table and continues to parse once at collect time inside RemoteCollectorService.BlockedProcessReport. Both SELECTs add `AND blocking_spid IS NOT NULL` so rows whose source XML carried an empty <blocking-process><process/></blocking-process> (system tasks, torn-down sessions) are filtered out — they can't contribute to a reconstructed chain. The old parser silently produced BlockingSpid = 0 for those rows, which the reconstructor's self-edge check then rejected anyway. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Schema-only PR (1 of 2) for the SQL-side blocked-process pair extraction work. Moves blocked-process-report XML parsing from analysis time to collection time so the Dashboard analysis path can read structured columns instead of re-parsing
blocked_process_report_xmlon everyBLOCKING_CHAINfact (up to 5000XElement.Parsecalls per cycle).Adds five typed columns to
collect.blocking_BlockedProcessReport:blocking_spid integerblocking_last_tran_started datetime2(7)blocking_status nvarchar(10)blocked_sql_text nvarchar(max)blocking_sql_text nvarchar(max)Names match the equivalent Lite DuckDB columns so the Dashboard and Lite analysis SQL can read identically-named columns.
What's in this PR
install/02_create_tables.sql— new columns added inside the existingIF OBJECT_ID(...) IS NULLtable-creation guard (fresh-install path).upgrades/2.11.0-to-2.12.0/01_extend_blocked_process_report_columns.sql— new upgrade script. Five idempotentIF NOT EXISTS / ALTER TABLE ADDblocks plus a one-pass backfill of existingactivity='blocked'rows.upgrades/2.11.0-to-2.12.0/upgrade.txt— manifest.install/23_process_blocked_process_xml.sql—collect.process_blocked_process_xmlnow populates the new typed columns at insert time from the XQuery(//blocked-process-report/blocking-process/process/@…)[1]shape, scoped to the freshly-parsed window. Runs before theis_processed=1mark so a crash rolls everything back and the raw XML rows stay unmarked for retry.Wire-format notes
The stored XML is
<event>-rooted with the report nested two levels deep at/event/data[@name="blocked_process"]/value/blocked-process-report. Both insertion paths (the raw collector ininstall/22andsp_HumanEventsBlockViewer's named-XE path) preserve this wrap. All XQuery in this PR uses the descendant axis//blocked-process-report/...to sidestep the two-level wrap; this was empirically validated againstsql2022.PerformanceMonitor(a leading-slash root path returns NULL on every row, descendant axis returns the expected attributes).Defense-in-depth
If
sp_HumanEventsBlockViewerwrites rows but the XQuery extraction populates zero typed columns, aTYPED_COLUMNS_EMPTYrow is written toconfig.collection_logso any future wire-format regression surfaces in telemetry instead of silently producing garbage chains in the analysis path.What's NOT in this PR
C# read-path simplification ships in a follow-up PR — deletion of
BlockedProcessXmlParser.csand switchingSqlServerFactCollector.CollectBlockingChainFactsAsync/SqlServerDrillDownCollector.CollectReconstructedBlockingChainsto read the new typed columns directly. That PR is gated on this one being ondev.Test plan
sql2022.PerformanceMonitor(5 ALTERs + 126-row backfill)collect.process_blocked_process_xmlALTER applied cleanlysql SELECT COUNT_BIG(*) FROM collect.blocking_BlockedProcessReport WHERE activity='blocked' AND blocked_process_report_xml IS NOT NULL AND blocking_spid IS NULL AND blocked_process_report_xml.exist(N'//blocked-process-report/blocking-process/process[@spid][1]') = 1;tsql-style-enforceragent — pass (one minor alias-qualification fix applied)upgrade-path-validatoragent — pass🤖 Generated with Claude Code