Skip to content

Per-database exclusions for collectors — Dashboard side (#887)#905

Merged
erikdarlingdata merged 1 commit intodevfrom
feature/887-per-database-exclusions
Apr 28, 2026
Merged

Per-database exclusions for collectors — Dashboard side (#887)#905
erikdarlingdata merged 1 commit intodevfrom
feature/887-per-database-exclusions

Conversation

@erikdarlingdata
Copy link
Copy Markdown
Owner

Summary

First half of #887. Adds a per-server, user-configurable list of databases to skip in the eight per-database collectors that iterate `sys.databases`.

What's in this PR

  • New table `config.collector_database_exclusions` (defined in `install/01`, mirrored into `config.ensure_config_tables` in `install/03`). No upgrade folder — installer re-runs `install/01` on existing installs and the `IF OBJECT_ID` guard handles it.
  • Eight collectors get a `NOT EXISTS (SELECT 1/0 FROM config.collector_database_exclusions WHERE database_name = d.name)` filter:
    • `query_stats` (08), `query_store` (09), `procedure_stats` (10), `file_io_stats` (20),
    • `waiting_tasks` (37), `database_configuration` (39), `database_size_stats` (52), `server_properties` (53).
  • Dashboard UI:
    • New Excluded Databases button on Manage Servers (between Check Server Version and Purge Now), with matching right-click entry.
    • Default window width 780 → 960 so all per-row buttons fit without resizing.
    • New `ExcludedDatabasesDialog` — live-queries `sys.databases` on the target, hides system DBs, pre-checks current exclusions, shows stale entries (in list but not on server) greyed and disabled with "(missing)" suffix.
  • `ServerManager` plumbing: `GetUserDatabasesAsync`, `GetCollectorDatabaseExclusionsAsync`, `SaveCollectorDatabaseExclusionsAsync` (transactional wipe + insert).

Not in this PR

Lite side. Lite stores the exclusion list in `servers.json` (no install on the target = no `config.collector_database_exclusions` table to use), and the collector queries are built C#-side, so the integration looks different. Following up as a separate PR.

Test plan

  • CLI installer ran end-to-end against sql2019 — 54/54 install scripts succeeded, 45/45 collectors validated.
  • All 8 collector procs verified to contain the new `config.collector_database_exclusions` reference after install.
  • Smoke test: excluded `hammerdb_tpcc` on sql2019 → `database_size_stats_collector` collected 0 rows for it while `StackOverflow2010` got 2 rows. Confirmed via transactional wrap-and-rollback so no real data was perturbed.
  • Dashboard build clean, dialog renders, save round-trips successfully.

Closes #887 when paired with the Lite follow-up PR.

New config.collector_database_exclusions table holds a per-server list of
user databases to skip in per-database collectors. The eight collectors
that iterate sys.databases now honor it via a NOT EXISTS filter:
query_stats, query_store, procedure_stats, file_io_stats, waiting_tasks,
database_configuration, database_size_stats, server_properties.

System databases (master/tempdb/model/msdb) and the PerformanceMonitor
database itself remain hardcoded skips in the collectors and are not
represented in the exclusions list.

Dashboard side:
- Manage Servers window gets a new "Excluded Databases" button (and matching
  context menu entry) between Check Server Version and Purge Now.
- Default window width bumped 780 → 960 so all per-row buttons fit on first
  open without resizing.
- New ExcludedDatabasesDialog modal: live-queries sys.databases on the
  target, pre-checks current exclusions, hides system DBs, shows stale
  entries (in list but not on server) greyed and disabled with "(missing)".
  Save replaces the table contents transactionally.
- ServerManager.GetUserDatabasesAsync, GetCollectorDatabaseExclusionsAsync,
  and SaveCollectorDatabaseExclusionsAsync handle the connection plumbing.

Schema is added in install/01 (initial install) and mirrored in install/03
inside config.ensure_config_tables (resilient re-creation). No upgrade
folder needed — installer re-runs install/01 on existing installs and the
IF OBJECT_ID guard fires.

Verified end-to-end by running the CLI installer against sql2019, then
excluding hammerdb_tpcc and confirming database_size_stats_collector
skipped it (0 rows) while StackOverflow2010 was still collected.

Lite side will follow in a separate PR (different storage model — Lite
keeps the exclusion list in servers.json since it doesn't install on
targets).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@erikdarlingdata erikdarlingdata merged commit 6c55dc6 into dev Apr 28, 2026
7 checks passed
@erikdarlingdata erikdarlingdata deleted the feature/887-per-database-exclusions branch April 28, 2026 02:30
pull Bot pushed a commit to ehtick/PerformanceMonitor that referenced this pull request Apr 29, 2026
Lite-side companion to PR erikdarlingdata#905 — gives users a per-server way to skip
specific databases in the per-database collectors.

Storage: ExcludedDatabases (List<string>) added to ServerConnection,
persisted via the existing servers.json round-trip. Lite doesn't install
on targets, so the list lives client-side instead of in a remote
config.collector_database_exclusions table the way Dashboard does it.

Wiring: 9 collectors get the filter — query_stats, query_store,
procedure_stats, query_snapshots, file_io_stats, waiting_tasks,
database_configuration, database_scoped_configurations, database_size.
Azure-mode collectors that route through GetAzureDatabaseListAsync get
exclusions automatically since the helper now applies the filter
centrally.

Two SQL helpers on RemoteCollectorService:
- BuildDatabaseExclusionFilter — parameterized AND <col> NOT IN (@excl_db_N).
  Used by every collector whose query is plain (non-dynamic) T-SQL.
  No compatibility-level dependency (avoids OPENJSON / STRING_SPLIT which
  require compat 130+ on the connection database).
- BuildDatabaseExclusionLiteralClause — N'name' literals with single-quote
  escaping (and a forNestedDynamicSql=true mode that doubles the escape).
  Used by procedure_stats which builds @SQL then passes to sp_executesql,
  where parameter binding inside the dynamic statement is awkward.
  Names come from a user-picked checklist, so literal interpolation with
  proper escaping is safe.

UI: ManageServersWindow gets a new "Excluded Databases" button between
Edit and Delete. Right-click context menu now mirrors the buttons —
Edit / Excluded Databases / Delete on top, then the existing
Copy/Export items below a separator. New ExcludedDatabasesDialog
mirrors the Dashboard version: live-queries sys.databases, hides system
DBs, pre-checks current exclusions, shows stale entries (in list but not
on server) greyed with "(missing)" tag. Save calls
ServerManager.UpdateServer to persist via servers.json.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant