Skip to content

Commit e6a93aa

Browse files
Merge pull request #500 from erikdarlingdata/feature/release-prep-2.2.0
v2.2.0 release prep: RDS fixes, USE removal, README sync
2 parents b196195 + f7db04e commit e6a93aa

9 files changed

Lines changed: 161 additions & 73 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,5 @@ nul
5454

5555
# Lite runtime configuration (user-specific)
5656
Lite/config/servers.json
57+
Lite/servers.json
5758
Lite/collection_schedule.json

CHANGELOG.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,62 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [2.2.0] - 2026-03-09
9+
10+
**Contributors:** [@HannahVernon](https://github.com/HannahVernon), [@ClaudioESSilva](https://github.com/ClaudioESSilva), [@dphugo](https://github.com/dphugo), [@Orestes](https://github.com/Orestes) — thank you!
11+
12+
### Important
13+
14+
- **Schema upgrade**: Three large collection tables (`query_stats`, `procedure_stats`, `query_store_data`) are migrated to use `COMPRESS()` for query text and plan columns, reducing storage by ~60-80%. The upgrade performs a table swap (create new → migrate data → rename) which may take several minutes on large tables. A `row_hash` column is added for deduplication. Three new tracking tables are also created. Volume stats columns are added to `database_size_stats`. Upgrade scripts run automatically via the CLI/GUI installer and use idempotent checks.
15+
16+
### Added
17+
18+
- **FinOps monitoring tab** — database size tracking, server properties, storage growth analysis (7d/30d), index analysis with unused/duplicate/compressible detection, utilization efficiency, idle database identification, and estate-level resource views ([#474])
19+
- **Named collection presets** — Aggressive, Balanced, and Low-Impact schedule profiles via `config.apply_collection_preset` ([#454])
20+
- **Entra ID interactive MFA authentication** in both CLI and GUI installers for Azure SQL MI connections ([#481])
21+
- **MCP port validation** — TCP port conflict detection, range validation (1024+), Auto port button, and auto-restart on settings change ([#453])
22+
- **Alert database exclusion filters** — filter blocking and deadlock alerts by database in both Dashboard and Lite ([#410], [#412])
23+
- **Configurable alert cooldown periods** for tray notifications and email alerts
24+
- **Wait stats query drill-down** — click a wait type to see the queries causing it ([#372])
25+
- **Configurable long-running query settings** — max results, WAITFOR/backup/diagnostics exclusions ([#415])
26+
- **Uninstall option** in both CLI and GUI installers ([#431])
27+
- **Session stats collector** for active session tracking ([#474])
28+
- **LOB compression and deduplication** for query stats tables to reduce storage ([#419])
29+
- **Volume-level drive space** enrichment in database size stats via `dm_os_volume_stats`
30+
- **GUI installer installation history** logging to `config.installation_history` ([#414])
31+
- CI version bump check on PRs to main
32+
- Permissions section in README with least-privilege setup ([#421])
33+
34+
### Changed
35+
36+
- **Utilization tab redesigned** — ported to Dashboard with aligned metrics between apps ([#478])
37+
- PlanAnalyzer rules synced from PerformanceStudio — Rule 5 message format, seek predicate parsing, spool labels, unmatched index detail ([#416], [#475], [#480])
38+
- Data retention now purges processed XE staging rows
39+
- GeneratedRegex conversion for compile-time regex patterns ([#346], [#420])
40+
- Server health card width increased from 260 to 300 for less text truncation ([#489])
41+
- User's locale used for date/time formatting in WPF bindings ([#459])
42+
- XML processing instructions stripped from sql_command/sql_text display
43+
- Parameterized queries in blocking/deadlock alert filtering
44+
45+
### Fixed
46+
47+
- **UI hang** when opening Dashboard tab for offline server — replaced synchronous `.GetAwaiter().GetResult()` with proper `await` ([#477])
48+
- **First-collection spike** skewing PerfMon, wait stats, file I/O, memory grant, query stats, and procedure stats charts — first cumulative value now treated as baseline ([#482])
49+
- **Wait type filter TextBox** too small to read ([#488])
50+
- **Poison wait false positives** and alert log parsing ([#445], [#448])
51+
- **RID Lookup** analyzer rule matching new PhysicalOp label ([#429])
52+
- **procedure_stats** plan query using DECOMPRESS after compression migration
53+
- **database_size_stats** InvalidCastException on compatibility_level
54+
- **Deadlock filter** using wrong column reference in `GetFilteredDeadlockCountAsync`
55+
- **RESTORING database** filter added to waiting_tasks collector ([#430])
56+
- Custom TrayToolTip crash — replaced with plain ToolTipText ([#422])
57+
- DuckDB read lock acquisition resilience
58+
- Formatted duration columns sorting alphabetically instead of numerically
59+
- Settings window staying open on validation errors
60+
- Deserialization clamping and validation abort issues
61+
62+
[2.2.0]: https://github.com/erikdarlingdata/PerformanceMonitor/compare/v2.1.0...v2.2.0
63+
864
## [2.1.0] - 2026-03-04
965

1066
### Important
@@ -371,3 +427,31 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
371427
[#393]: https://github.com/erikdarlingdata/PerformanceMonitor/issues/393
372428
[#289]: https://github.com/erikdarlingdata/PerformanceMonitor/issues/289
373429
[#395]: https://github.com/erikdarlingdata/PerformanceMonitor/issues/395
430+
[#400]: https://github.com/erikdarlingdata/PerformanceMonitor/issues/400
431+
[#401]: https://github.com/erikdarlingdata/PerformanceMonitor/issues/401
432+
[#410]: https://github.com/erikdarlingdata/PerformanceMonitor/issues/410
433+
[#412]: https://github.com/erikdarlingdata/PerformanceMonitor/issues/412
434+
[#414]: https://github.com/erikdarlingdata/PerformanceMonitor/issues/414
435+
[#415]: https://github.com/erikdarlingdata/PerformanceMonitor/issues/415
436+
[#416]: https://github.com/erikdarlingdata/PerformanceMonitor/issues/416
437+
[#419]: https://github.com/erikdarlingdata/PerformanceMonitor/issues/419
438+
[#420]: https://github.com/erikdarlingdata/PerformanceMonitor/issues/420
439+
[#421]: https://github.com/erikdarlingdata/PerformanceMonitor/issues/421
440+
[#422]: https://github.com/erikdarlingdata/PerformanceMonitor/issues/422
441+
[#429]: https://github.com/erikdarlingdata/PerformanceMonitor/issues/429
442+
[#430]: https://github.com/erikdarlingdata/PerformanceMonitor/issues/430
443+
[#431]: https://github.com/erikdarlingdata/PerformanceMonitor/issues/431
444+
[#445]: https://github.com/erikdarlingdata/PerformanceMonitor/issues/445
445+
[#448]: https://github.com/erikdarlingdata/PerformanceMonitor/issues/448
446+
[#453]: https://github.com/erikdarlingdata/PerformanceMonitor/issues/453
447+
[#454]: https://github.com/erikdarlingdata/PerformanceMonitor/issues/454
448+
[#459]: https://github.com/erikdarlingdata/PerformanceMonitor/issues/459
449+
[#474]: https://github.com/erikdarlingdata/PerformanceMonitor/issues/474
450+
[#475]: https://github.com/erikdarlingdata/PerformanceMonitor/issues/475
451+
[#477]: https://github.com/erikdarlingdata/PerformanceMonitor/issues/477
452+
[#478]: https://github.com/erikdarlingdata/PerformanceMonitor/issues/478
453+
[#480]: https://github.com/erikdarlingdata/PerformanceMonitor/issues/480
454+
[#481]: https://github.com/erikdarlingdata/PerformanceMonitor/issues/481
455+
[#482]: https://github.com/erikdarlingdata/PerformanceMonitor/issues/482
456+
[#488]: https://github.com/erikdarlingdata/PerformanceMonitor/issues/488
457+
[#489]: https://github.com/erikdarlingdata/PerformanceMonitor/issues/489

Lite/Services/RemoteCollectorService.DatabaseSize.cs

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -42,25 +42,43 @@ used_size_mb decimal(19,2) NULL
4242
);
4343
4444
DECLARE
45-
@sql nvarchar(MAX) = N'';
45+
@db_name sysname,
46+
@sql nvarchar(MAX);
4647
47-
SELECT
48-
@sql += N'
49-
USE ' + QUOTENAME(d.name) + N';
48+
DECLARE db_cursor CURSOR LOCAL FAST_FORWARD FOR
49+
SELECT
50+
d.name
51+
FROM sys.databases AS d
52+
WHERE d.state_desc = N'ONLINE'
53+
AND d.database_id > 0
54+
AND HAS_DBACCESS(d.name) = 1
55+
ORDER BY
56+
d.name;
57+
58+
OPEN db_cursor;
59+
FETCH NEXT FROM db_cursor INTO @db_name;
60+
61+
WHILE @@FETCH_STATUS = 0
62+
BEGIN
63+
BEGIN TRY
64+
SET @sql = N'EXECUTE ' + QUOTENAME(@db_name) + N'.sys.sp_executesql N''
5065
INSERT #file_space (database_id, file_id, used_size_mb)
5166
SELECT
5267
DB_ID(),
5368
df.file_id,
54-
CONVERT(decimal(19,2), FILEPROPERTY(df.name, N''SpaceUsed'') * 8.0 / 1024.0)
55-
FROM sys.database_files AS df;
56-
'
57-
FROM sys.databases AS d
58-
WHERE d.state_desc = N'ONLINE'
59-
AND d.database_id > 0
60-
ORDER BY
61-
d.name;
69+
CONVERT(decimal(19,2), FILEPROPERTY(df.name, N''''SpaceUsed'''') * 8.0 / 1024.0)
70+
FROM sys.database_files AS df;'';';
71+
72+
EXECUTE sys.sp_executesql @sql;
73+
END TRY
74+
BEGIN CATCH
75+
END CATCH;
76+
77+
FETCH NEXT FROM db_cursor INTO @db_name;
78+
END;
6279
63-
EXEC sys.sp_executesql @sql;
80+
CLOSE db_cursor;
81+
DEALLOCATE db_cursor;
6482
6583
SELECT
6684
database_name = d.name,

Lite/Services/RemoteCollectorService.QueryStore.cs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ Uses sys.database_query_store_options.actual_state instead of
4141
4242
DECLARE
4343
@db sysname,
44-
@sql NVARCHAR(500);
44+
@sql NVARCHAR(500),
45+
@exec_sp nvarchar(256);
4546
4647
DECLARE db_check CURSOR LOCAL FAST_FORWARD FOR
4748
SELECT /* PerformanceMonitorLite */
@@ -70,8 +71,7 @@ FROM db_check
7071
WHILE @@FETCH_STATUS = 0
7172
BEGIN
7273
BEGIN TRY
73-
SET @sql =
74-
N'USE ' + QUOTENAME(@db) + N';
74+
SET @sql = N'
7575
SELECT ' + QUOTENAME(@db, '''') + N'
7676
WHERE EXISTS
7777
(
@@ -81,8 +81,10 @@ FROM sys.database_query_store_options
8181
WHERE actual_state > 0
8282
);';
8383
84+
SET @exec_sp = QUOTENAME(@db) + N'.sys.sp_executesql';
85+
8486
INSERT @result (name)
85-
EXEC(@sql);
87+
EXECUTE @exec_sp @sql;
8688
END TRY
8789
BEGIN CATCH
8890
END CATCH;
@@ -110,7 +112,8 @@ ORDER BY
110112
111113
DECLARE
112114
@db sysname,
113-
@sql NVARCHAR(500);
115+
@sql NVARCHAR(500),
116+
@exec_sp nvarchar(256);
114117
115118
DECLARE db_check CURSOR LOCAL FAST_FORWARD FOR
116119
SELECT /* PerformanceMonitorLite */
@@ -131,8 +134,7 @@ FROM db_check
131134
WHILE @@FETCH_STATUS = 0
132135
BEGIN
133136
BEGIN TRY
134-
SET @sql =
135-
N'USE ' + QUOTENAME(@db) + N';
137+
SET @sql = N'
136138
SELECT ' + QUOTENAME(@db, '''') + N'
137139
WHERE EXISTS
138140
(
@@ -142,8 +144,10 @@ FROM sys.database_query_store_options
142144
WHERE actual_state > 0
143145
);';
144146
147+
SET @exec_sp = QUOTENAME(@db) + N'.sys.sp_executesql';
148+
145149
INSERT @result (name)
146-
EXEC(@sql);
150+
EXECUTE @exec_sp @sql;
147151
END TRY
148152
BEGIN CATCH
149153
END CATCH;

README.md

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ Both editions include real-time alerts (system tray + email), charts and graphs,
3838

3939
## What You Get
4040

41-
🔍 **32 specialized T-SQL collectors** running on configurable schedules — wait stats, query performance, blocking chains, deadlock graphs, memory grants, file I/O, tempdb, perfmon counters, and more. Query text and execution plan collection can be disabled per-collector for sensitive environments.
41+
🔍 **32 specialized T-SQL collectors** running on configurable schedules with named presets (Aggressive, Balanced, Low-Impact) — wait stats, query performance, blocking chains, deadlock graphs, memory grants, file I/O, tempdb, perfmon counters, FinOps/capacity, and more. Query text and execution plan collection can be disabled per-collector for sensitive environments.
4242

4343
🚨 **Real-time alerts** for blocking, deadlocks, and high CPU — system tray notifications plus styled HTML emails with full XML attachments for offline analysis
4444

@@ -81,7 +81,7 @@ Data starts flowing within 1–5 minutes. That's it. No installation on your ser
8181

8282
### Lite Collectors
8383

84-
20 collectors run on independent, configurable schedules:
84+
23 collectors run on independent, configurable schedules:
8585

8686
| Collector | Default | Source |
8787
|---|---|---|
@@ -98,9 +98,12 @@ Data starts flowing within 1–5 minutes. That's it. No installation on your ser
9898
| tempdb_stats | 1 min | `sys.dm_db_file_space_usage` |
9999
| perfmon_stats | 1 min | `sys.dm_os_performance_counters` (deltas) |
100100
| deadlocks | 1 min | `system_health` Extended Events session |
101+
| session_stats | 1 min | `sys.dm_exec_sessions` active session tracking |
101102
| memory_clerks | 5 min | `sys.dm_os_memory_clerks` |
102103
| query_store | 5 min | Query Store DMVs (per database) |
103104
| running_jobs | 5 min | `msdb` job history with duration vs avg/p95 |
105+
| database_size_stats | 15 min | `sys.master_files` + `FILEPROPERTY` + `dm_os_volume_stats` |
106+
| server_properties | 15 min | `SERVERPROPERTY()` hardware and licensing metadata |
104107
| server_config | On connect | `sys.configurations` |
105108
| database_config | On connect | `sys.databases` |
106109
| database_scoped_config | On connect | Database-scoped configurations |
@@ -141,13 +144,26 @@ SQL Authentication:
141144
PerformanceMonitorInstaller.exe YourServerName sa YourPassword
142145
```
143146

147+
Entra ID (MFA) Authentication:
148+
149+
```
150+
PerformanceMonitorInstaller.exe YourServerName --entra user@domain.com
151+
```
152+
144153
Clean reinstall (drops existing database and all collected data):
145154

146155
```
147156
PerformanceMonitorInstaller.exe YourServerName --reinstall
148157
PerformanceMonitorInstaller.exe YourServerName sa YourPassword --reinstall
149158
```
150159

160+
Uninstall (removes database, Agent jobs, and XE sessions):
161+
162+
```
163+
PerformanceMonitorInstaller.exe YourServerName --uninstall
164+
PerformanceMonitorInstaller.exe YourServerName sa YourPassword --uninstall
165+
```
166+
151167
The installer automatically tests the connection, executes SQL scripts, downloads community dependencies, creates SQL Agent jobs, and runs initial data collection. A GUI installer (`InstallerGui/`) is also available with the same functionality.
152168

153169
### CLI Installer Options
@@ -156,7 +172,10 @@ The installer automatically tests the connection, executes SQL scripts, download
156172
|---|---|
157173
| `SERVER` | SQL Server instance name (positional, required) |
158174
| `USERNAME PASSWORD` | SQL Authentication credentials (positional, optional) |
175+
| `--entra EMAIL` | Microsoft Entra ID interactive authentication (MFA) |
159176
| `--reinstall` | Drop existing database and perform clean install |
177+
| `--uninstall` | Remove database, Agent jobs, and XE sessions |
178+
| `--reset-schedule` | Reset collection schedule to recommended defaults |
160179
| `--preserve-jobs` | Keep existing SQL Agent job schedules during upgrade |
161180
| `--encrypt=optional\|mandatory\|strict` | Connection encryption level (default: mandatory) |
162181
| `--trust-cert` | Trust server certificate without validation (default: require valid cert) |
@@ -175,6 +194,7 @@ The installer automatically tests the connection, executes SQL scripts, download
175194
| `4` | Partial installation (non-critical failures) |
176195
| `5` | Version check failed |
177196
| `6` | SQL files not found |
197+
| `7` | Uninstall failed |
178198

179199
### Post-Installation
180200

@@ -264,7 +284,7 @@ The Full Edition supports Azure SQL Managed Instance and AWS RDS for SQL Server
264284
| AWS RDS for SQL Server | Supported | Supported |
265285
| Azure SQL Database | Not supported | Supported |
266286
| Multi-server from one seat | Per-server install | Built-in |
267-
| Collectors | 32 | 20 |
287+
| Collectors | 32 | 23 |
268288
| Agent job monitoring | Duration vs historical avg/p95 | Duration vs historical avg/p95 |
269289
| Data storage | SQL Server (on target) | DuckDB + Parquet (local) |
270290
| Execution plans | Collected and stored (can be disabled per-collector) | Download on demand |
@@ -308,6 +328,7 @@ Plus a NOC-style landing page with server health cards (green/yellow/red severit
308328
| **Blocking** | Blocking/deadlock trends, blocked process reports, deadlock history |
309329
| **Perfmon** | Selectable SQL Server performance counters over time |
310330
| **Configuration** | Server configuration, database configuration, scoped configuration, trace flags |
331+
| **FinOps** | Database size tracking, storage growth analysis (7d/30d), server properties, capacity planning |
311332

312333
Both editions feature auto-refresh, configurable time ranges, right-click CSV export, system tray integration, dark and light themes, and timezone display options (server time, local time, or UTC).
313334

@@ -545,7 +566,7 @@ Use the RDS master user for installation. The master user has the necessary perm
545566
Monitor/
546567
547568
│ Full Edition (server-installed collectors + separate dashboard)
548-
├── install/ # 54 SQL installation scripts
569+
├── install/ # 58 SQL installation scripts
549570
├── upgrades/ # Version-specific upgrade scripts
550571
├── Installer/ # CLI installer for Full Edition database (C#)
551572
├── InstallerGui/ # GUI installer for Full Edition database (WPF)

install/09_collect_query_store.sql

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -324,8 +324,7 @@ BEGIN
324324
WHILE @@FETCH_STATUS = 0
325325
BEGIN
326326
BEGIN TRY
327-
SET @qs_check_sql =
328-
N'USE ' + QUOTENAME(@database_name) + N';
327+
SET @qs_check_sql = N'
329328
SELECT ' + QUOTENAME(@database_name, '''') + N'
330329
WHERE EXISTS
331330
(
@@ -335,8 +334,10 @@ BEGIN
335334
WHERE actual_state > 0
336335
);';
337336

337+
DECLARE @qs_exec_sp nvarchar(256) = QUOTENAME(@database_name) + N'.sys.sp_executesql';
338+
338339
INSERT @qs_databases (name)
339-
EXEC(@qs_check_sql);
340+
EXECUTE @qs_exec_sp @qs_check_sql;
340341
END TRY
341342
BEGIN CATCH
342343
END CATCH;

install/52_collect_database_size_stats.sql

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ BEGIN
178178
FROM sys.databases AS d
179179
WHERE d.state_desc = N'ONLINE'
180180
AND d.database_id > 0
181+
AND HAS_DBACCESS(d.name) = 1
181182
ORDER BY
182183
d.database_id;
183184

@@ -188,8 +189,6 @@ BEGIN
188189
BEGIN
189190
BEGIN TRY
190191
SET @sql = N'
191-
USE ' + QUOTENAME(@db_name) + N';
192-
193192
INSERT INTO
194193
PerformanceMonitor.collect.database_size_stats
195194
(
@@ -255,7 +254,9 @@ BEGIN
255254
CROSS APPLY sys.dm_os_volume_stats(DB_ID(), df.file_id) AS vs
256255
WHERE d.database_id = DB_ID();';
257256

258-
EXECUTE sys.sp_executesql
257+
DECLARE @exec_sql nvarchar(max) = QUOTENAME(@db_name) + N'.sys.sp_executesql';
258+
259+
EXECUTE @exec_sql
259260
@sql,
260261
N'@start_time datetime2(7)',
261262
@start_time = @start_time;

0 commit comments

Comments
 (0)