Repository navigation
Fix QUERY_HIGH_DOP firing on a stale lifetime max_dop - #2706
Conversation
v_query_stats.max_dop is sys.dm_exec_query_stats' lifetime-max for a plan's time in cache - the same semantics QueryStatExtremes.cs already documents for min/max_cpu_ms, and the same caveat get_top_queries_by_cpu's tool description has always carried for a human reader. QUERY_HIGH_DOP had no equivalent guard: it counted max_dop > 8 unconditionally and fed the raw lifetime value into a Fact at full confidence, so a plan compiled before an operator lowered MAXDOP kept tripping the finding forever. Apply the same provable-tell doctrine QueryStatExtremes uses for CPU and elapsed extremes: a max_dop reading that exceeds the server's CURRENT max degree of parallelism setting is impossible under today's config, so it provably predates whatever change set that config and must not be counted. A current value of 0 (unlimited) or no server_config row at all proves nothing impossible, so the count is unchanged in both cases. Verified against a live Postgres 17 container: reverting the fix reproduces the exact reported false positive (maxdop=1, stale max_dop=16 still fires QUERY_HIGH_DOP); restoring it suppresses that case while leaving the maxdop=0 and unknown-config cases firing exactly as before. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
ReviewThe Darling-side fix itself looks correct: the Lite/Darling parity drift This fixes only the Darling collector. |
Fixes #2705.
Problem
`PgFactCollector.CollectQueryStatsFactsAsync` counted `v_query_stats.max_dop > 8` unconditionally and fed the count into a `QUERY_HIGH_DOP` Fact at full confidence. `max_dop` is `sys.dm_exec_query_stats`' lifetime-max for the plan's time in cache — the exact semantics `PerformanceMonitor.Common/QueryStatExtremes.cs` (#2235) already documents for `min/max_cpu_ms`, and the same caveat `get_top_queries_by_cpu`'s tool description has always carried. A plan compiled before an operator lowered `max degree of parallelism` keeps reporting its old, higher DOP until evicted or recompiled — so on a server now configured to MAXDOP 1, a cached `max_dop = 16` is not a current problem, it's a stale high-water mark, and the finding fired anyway at severity 1.00.
Fix
Same "provable tell" doctrine `QueryStatExtremes` already applies to CPU/elapsed: a `max_dop` reading that exceeds the server's current `max degree of parallelism` (from `server_config`) is impossible under today's configuration, so it provably predates whatever change set that config, and is excluded from the count. A current value of 0 (unlimited) or no `server_config` row at all proves nothing impossible, so those cases are unchanged.
Test plan
🤖 Generated with Claude Code