Skip to content

query_stats.creation_time is compared against a naive-UTC bound, so PARAMETER_SENSITIVITY is scored against the wrong plan population #2991

Description

@erikdarlingdata

query_stats.creation_time is compared against a naive-UTC bound, so PARAMETER_SENSITIVITY is scored against the wrong plan population on every non-UTC server

Confirmed live on the production fleet, not hypothetical. Every production SQL Server target reports utc_offset_minutes = -240 (UTC-4). The only target at 0 is a dev box. So this affects the whole monitored SQL Server fleet across both stores, not one server's configuration quirk.

The defect

Six sites compare a server-local column against a bound derived from DateTime.UtcNow:

  • Darling/PerformanceMonitor.Darling.Analysis/PgFactCollector.QueryPerf.cs
  • Darling/PerformanceMonitor.Darling.Analysis/PgDrillDownCollector.Queries.cs (two sites)
  • Lite/Analysis/DuckDbFactCollector.QueryPerf.cs
  • Lite/Analysis/DrillDownCollector.Queries.cs (two sites)

Each reads creation_time <= $n, where $n is AnalysisContext.TimeRangeStart — which both analysis services derive from DateTime.UtcNow. query_stats.creation_time is the monitored server's local clock (documented at QueryStatsCollector.cs:167).

Why the predicate exists, and what breaks

The predicate means "this plan was compiled before the analysis window opened." That is what makes a large min/max worker-time spread evidence of parameter sensitivity rather than of a plan that simply has not lived long enough to have seen varied parameters yet. It is the guard that separates a real signal from an artefact of plan age.

At UTC-4 the arithmetic works out as follows. A plan compiled at UTC instant T is stored with creation_time = T - 4h. The predicate therefore admits any plan where T - 4h <= W, i.e. T <= W + 4h, where W is the window start. On the default 4-hour window the window is [W, W + 4h] — so the predicate admits every plan compiled inside the window, which is precisely the population it exists to exclude.

A negative offset is the false-positive direction. Recently-compiled plans are admitted, and their partial-life worker-time spread is scored as if it were full-life variance. So PARAMETER_SENSITIVITY facts and the drill-downs hanging off them have been generated against the wrong population fleet-wide — over-reporting rather than silently suppressing.

For completeness, the other direction is worse but does not apply here: at a positive offset (say UTC+10) the predicate admits only plans compiled at least 10 hours before the window, so on a 4-hour window essentially nothing qualifies and the finding class silently stops being produced altogether. Any deployment east of UTC gets that behaviour instead.

Scope note

AnalysisContext.ServerUtcOffset exists but is TimeSpan.Zero in both live SKUs. The only non-zero assignment in the tree is in the retired Dashboard project, and its semantic is the inverse — it converts a server-local window back to UTC for persistence — so it is not the seam to reuse without deciding what it means here.

The retired Dashboard carries the same shape at Analysis/SqlServerFactCollector.QueryPerf.cs, Analysis/SqlServerDrillDownCollector.Queries.cs and Services/DatabaseService.QueryPerformance.Stats.cs. Out of scope unless that SKU is still shipped.

Not verified

The predicted effect on findings output has not been measured against stored analysis_findings rows — that comparison would confirm the over-reporting empirically and is the obvious next step, but it needs a store query rather than source reading. Nobody has checked whether the finding counts actually look inflated.

The fix direction is a per-server de-skew in SQL from the collected server_properties.utc_offset_minutes, which is the pattern already used elsewhere in this codebase. That is six SQL edits across two dialects and it changes what the detector emits, so it wants live verification rather than a source-only change.

No activity

Activity on this issue will appear here.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions