Skip to content

[BUG] planwm/backfill state pruning does not reach Azure SQL DB #2191

Description

@erikdarlingdata

Split out of #2188 while implementing it, so the residual is recorded rather than implied by a code comment.

#2188 prunes the per-database collector_state rows query_store accumulates (planwm: under query_store_plan_xml, done: / hole: under query_store_backfill) by anti-joining against the newest database_states snapshot for the server. That snapshot is an unfiltered SELECT ... FROM sys.databases, which is the only list in the store that answers "does this database still exist" without confusing a dropped database for an offline, excluded, or unprobeable one.

DatabaseStateCollector.AppliesTo is !target.IsAzureSqlDb, so an Azure SQL DB server has no such snapshot. The prune statement is guarded on the snapshot existing (an unguarded anti-join against an empty snapshot deletes every row), so on Azure it correctly no-ops — and those orphans therefore accumulate unpruned.

Azure SQL DB does write these rows: QueryStoreCollector.ReadAsync (the per-database Azure path) and ReadItemAsync (the on-prem enumerated path) both route through ReadRowsAsync, which holds the watermark write-back, and Darling sets CapturePlanXml on both.

Why the obvious fix is wrong

The per-cycle Azure database list from DarlingCollectorRunner.GetAzureDatabaseListAsync is NOT authoritative for existence, in three separate ways:

  • it filters state_desc = N'ONLINE', so a paused or offline database is absent while still existing;
  • it applies the per-server excluded-database filter;
  • on a master-access error it falls back to the connection's own single database ([QUESTION] Connection is broken: need PM restart ? #1506), which as a prune input would delete every other database's state on the logical server.

Pruning against it would delete live watermarks on exactly the servers that have excluded or intermittently-offline databases — the same self-defeating shape #2188's issue text warns about for the on-prem enumeration.

What a fix would need

An authoritative unfiltered sys.databases name list read from the logical master, used only when the master read actually succeeded (never on the fallback path). That is reachable — the Azure enumeration already opens a master connection — but getting it without either a second master connection per cycle or reshaping the existing enumeration query is a design call, which is why it is not folded into #2188.

Severity

Cosmetic, same as #2188: an orphaned row is never read again, and the accumulation is bounded to one ~100-byte row per database name ever seen. Worth doing on a logical server with churny database provisioning, not urgent anywhere.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions