Skip to content

Release v2.0.0#299

Merged
erikdarlingdata merged 97 commits intomainfrom
dev
Feb 26, 2026
Merged

Release v2.0.0#299
erikdarlingdata merged 97 commits intomainfrom
dev

Conversation

@erikdarlingdata
Copy link
Owner

Summary

v2.0.0 release — 93 commits since v1.3.0. Major additions across Dashboard, Lite, and Installer.

New features

Bug fixes

  • Plan button silent failure fixes (6 handlers across Dashboard + Lite)
  • Server timezone race condition fix
  • Fix missing chart context menu on File I/O Throughput charts in Lite
  • Installer: TRUNCATE TABLE database context fix (three-part name)
  • Installer: Version comparison bug fix (3-part vs 4-part normalization)
  • GUI Installer: Upgrade detection fix (AppAssemblyVersion vs AppVersion)

Improvements

  • SQL Agent job cleanup when removing a server via Dashboard (all 3 jobs)
  • RemoveServerDialog text updated to mention Agent job removal
  • session_wait_stats fully removed (zero UI references, full cleanup)
  • Upgrade scripts for v1.3.0 → v2.0.0 (memory_grant_stats schema, session_wait_stats cleanup)

Test plan

  • Fresh install on sql2016 — 51/51 scripts, 46 collectors
  • Upgrade v1.3.0 → v2.0.0 on sql2016 — upgrade found and applied correctly
  • Idempotent re-run on sql2016 — no upgrades, 51/51 scripts, 46 collectors
  • GUI upgrade on sql2025 — both upgrade paths found and applied
  • Agent job cleanup verified — all 3 jobs removed on DB drop
  • Dashboard and Lite build successfully
  • Upgrade tested on sql2017 and sql2025

🤖 Generated with Claude Code

erikdarlingdata and others added 30 commits February 21, 2026 15:29
…ystem (#218)

Root cause: archival DELETEs + CHECKPOINT reorganized/truncated the DuckDB file
while UI connections had stale file offsets, causing "Reached the end of the file"
crashes after ~1 hour of uptime.

Fix: ReaderWriterLockSlim coordinates UI readers with maintenance writers. UI queries
hold read locks (unlimited concurrency) via LockedConnection wrapper. CHECKPOINT and
archive DELETEs hold exclusive write locks (<1s duration).

Maintenance overhaul:
- Replaced compaction cycle (File.Replace race condition) with archive-all-and-reset
- Size-based trigger at 512MB archives ALL data to parquet, deletes .duckdb, reinits
- Tested: 515MB → 19MB in <1s, 65K rows to ~400KB ZSTD parquet per cycle
- Per-reset timestamped parquet naming (20260221_1925_table.parquet) eliminates
  merge logic and simplifies 90-day retention (delete by date prefix)
- RetentionService handles both new timestamped and legacy monthly formats
- Wired AppLoggerAdapter<T> for all 8 services that had null loggers
- Removed dead CompactAsync method (~140 lines)

Tested with 4 SQL Servers under HammerDB load, 3 successful archive+reset cycles,
zero errors, archive views correctly serve data from all parquet file sets.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…r-corruption

Fix DuckDB file corruption during maintenance (#218)
…kDB-first plans, lock wait trend, clipboard fix, procedure stats parity

Issues addressed:
- #185: Consolidate Server/Database/Trace Flag config change tabs into single ConfigChangesContent UserControl with sub-tabs (Dashboard)
- #201: Add option to drop PerformanceMonitor database when removing a server, with confirmation dialog (Dashboard)
- #219: Try DuckDB cache first for query plan downloads before falling back to live server (Lite)
- #141: Add lock waits trend chart to Blocking > Trends tab with multi-series per LCK% wait type (Lite)

Additional fixes:
- Fix clipboard copy: "Copy All Rows" and "Export to CSV" context menu items now extract TextBlock text from StackPanel column headers instead of showing "System.Windows.Controls.StackPanel" (both apps, 22 call sites)
- Add missing columns to Lite procedure stats grid: Total Spills, Min/Max CPU, Min/Max Duration, Plan Handle, and Download Plan button with DuckDB-first lookup
- Filter out zero-activity rows from query stats and procedure stats grids (HAVING clause on delta sums)
- Make query stats grid plan download DuckDB-first (was live-server only)
- Fix plan download button text resetting to "Save" instead of "Download"

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ig-changes

v1.4.0: Config consolidation, DB drop, DuckDB-first plans, lock wait chart, clipboard fix
Memory clerks data was already being collected but had no UI. Added a
Memory Clerks sub-tab under Memory with a type picker (matching the
wait stats pattern), trend chart showing MB over time per clerk type,
and a summary footer showing non-buffer-pool total and top clerk.

Also added missing DuckDB index on memory_clerks(server_id, collection_time).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Lite: Add memory clerks tab with picker-driven chart (#145)
…cators (#110)

- Add sort direction arrows to DataGrid column headers via custom ControlTemplate
  with Path geometry and SortDirection triggers (both Dashboard and Lite themes)
- Right-align ~321 numeric columns across both projects using NumericCell ElementStyle
- Show initial sort arrow on pre-sorted grids (Query Stats, Proc Stats, Query Store,
  Regressions, Long Running Patterns) so users see current sort before clicking

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Visual polish: sort arrows, right-aligned numerics, initial sort indicators (#110)
)

Port duration trends chart from Lite to Dashboard. Shows per-collector
execution times over 24h with one colored line per collector.
Excludes scheduled_master_collector to keep individual collector
durations readable. Wired into parallel refresh flow.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…on-chart

Add collector duration trends chart to Dashboard (#138)
Collection log drill-down: double-click a collector in Health Summary
to see its full history (runs, duration breakdown, errors).

Daily summary: new tab with date picker showing aggregated daily
metrics — total waits, top wait type, deadlocks, blocking, high CPU,
and collection errors for the selected day.

Closes #138

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…log-drilldown

Add collection log drill-down and daily summary to Lite (#138)
Dashboard: New "Current Active Queries" sub-tab under Queries that runs
dm_exec_requests directly against the server for a live view of running
queries. Independent refresh button, column filtering, and query plan
download (.sqlplan) from in-memory results. No PerformanceMonitor DB
involvement — pure DMV snapshot.

Lite: "Live Snapshot" button on Active Queries tab runs the same collector
query directly against the server, bypassing DuckDB. Results populate the
existing grid with a gold "LIVE at HH:mm:ss" indicator that clears on
next auto-refresh.

Both: Enhanced query with 5 new columns from dm_exec_sessions — login_name,
host_name, program_name, open_transaction_count, percent_complete. Lite
schema bumped to v12 with ALTER TABLE migration.

Tested on sql2022 and sql2016.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Current Active Queries live snapshot view (#149)
- Add --help/-h flag to CLI installer showing usage, options, env vars, and exit codes
- Fix Lite status bar text from gray (ForegroundMutedBrush) to white (ForegroundBrush) for readability

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add CLI --help flag and fix Lite status bar text (#111)
Phase 1: ShowPlanXML rendering as interactive operator graph in a new
Plan Viewer tab. Right-click any query row → View Estimated Plan to
parse and display the plan inline (fetches on-demand when needed).

- LINQ-to-XML parser with cost computation, warnings, missing indexes
- SSMS-style layout: left-to-right with first-child horizontal spine
- 113 MIT-licensed operator icons from vscode-mssql
- Synthetic SELECT/INSERT/UPDATE/DELETE root node
- Rich tooltips, zoom/pan, save .sqlplan, multi-statement selector
- Missing index banner with CREATE INDEX suggestions
- Warnings banner (spills, implicit conversions, no join predicate)
- View Actual Plan menu item stubbed for Phase 2 (query execution)

Tested on sql2022 with TPC-H plans. Both apps build clean.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add collapsible properties panel (right-side, GridSplitter) with node selection
- Add rich tooltips with costs, rows, I/O, predicates, output columns
- Parse ~30 new operator properties: OrderBy, GroupBy, DefinedValues,
  OuterReferences, join columns, adaptive join, extended I/O stats,
  scan hints (ForcedIndex/ForceScan/ForceSeek/NoExpandHint), etc.
- Fix XML scoping bug: ScopedDescendants() prevents child RelOp property
  leakage (seek predicates, object names no longer bleed to parent operators)
- Fix EstimatedRowsRead/TableCardinality parsing (attributes are on RelOp,
  not the physical operator element)
- Fix DefinedValues to include column-only entries (no scalar expression)
- Gate Statement Memory Grant and Statement Info to root node only
- Always show boolean properties (Ordered, ForceScan, etc.) for scan/seek ops
- Always show I/O/CPU costs, rebinds/rewinds, estimated executions
- Add node context menus (Properties, Copy Operator/Object/Predicate)
- Statement-level metadata: CE version, DOP, compile stats, query hashes

Both Dashboard and Lite updated and tested against SSMS properties output.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…nt_complete type cast (#234)

- UNION ALL → UNION ALL BY NAME in archive views so schema migrations
  don't break parquet unions (query_snapshots grid was empty)
- Lazy<HashSet<string>> for ignored wait types to prevent concurrent
  HashSet corruption when multiple servers collect in parallel
- Convert.ToDecimal for percent_complete (dm_exec_requests returns real,
  not decimal)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…-union-234

Fix archive view column mismatch, wait_stats thread-safety, percent_complete cast, status bar color
Parse all operator-specific attributes per ShowPlan XSD schema:
- RelOp: Partitioned, IsAdaptive/AdaptiveThresholdRows/EstimatedJoinType
  (fixed: these are on <RelOp>, not the physical operator element)
- IndexScan: Lookup, DynamicSeek
- NestedLoops: Optimized, WithOrderedPrefetch, WithUnorderedPrefetch
- Sort: Distinct
- Filter: StartupExpression
- Top: WithTies
- Hash: BitmapCreator
- Parallelism: Remoting, LocalParallelism

Fix Lite ViewEstimatedPlan_Click missing switch cases:
- ProcedureStatsRow: fetch via FetchProcedurePlanOnDemandAsync
- QueryStoreRow: fetch via FetchQueryStorePlanAsync

Both apps build clean, properties panel displays all new attributes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
xunit is deprecated, they reccomend using xunit.v3 instead.
warning xUnit1051: Calls to methods which accept CancellationToken should use TestContext.Current.CancellationToken to allow test cancellation to be more responsive. (https://xunit.net/xunit.analyzers/rules/xUnit1051)
Wave 1 bug fixes: StatementEstRows int→double, IsMemoryGrantFeedbackAdjusted
bool→string (shows actual feedback status), CE version read from StmtSimple.

Wave 2 high priority: Merge/NL residual+PassThru predicates, stale stats warning,
per-operator memory grants, MaxQueryMemory, Parallelism HashKeys, Top offset/rows,
QueryPlan-level warnings.

Wave 3 medium priority: EffectiveDOP, MemoryFractions, RunTimePartitionSummary,
PlanGuide/UsePlan, ParameterizedText, QS hints, enhanced spill details, Spool
stack/PrimaryNodeId, Update DML sort/ActionColumn, columnstore segment stats,
UDF timing, TraceFlags, IndexedViewInfo, EstimatedDOP per-operator.

Wave 4 structural: StmtCond (IF/ELSE recursive parsing), StmtCursor with cursor
metadata and operation sub-plans.

All changes applied to both Dashboard and Lite. Both build clean, 0 errors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…etention (#237)

The data retention procedure now reads retention_days from
config.collection_schedule for each table instead of using a hardcoded
30-day value. Direct name matching handles most tables; special mappings
cover HealthParser, blocking_BlockedProcessReport, and deadlocks tables.
The @retention_days parameter remains as a fallback for unmatched tables.

The SQL Agent job step no longer passes @retention_days = 30, letting the
procedure use per-collector settings by default.

Tested on sql2022: query_snapshots used 10-day retention, running_jobs
used 7-day retention, batch deletion confirmed working with @batch_size = 1000.

Closes #237

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…tention-237

Use per-collector retention from collection_schedule (#237)
erikdarlingdata and others added 29 commits February 24, 2026 22:30
…rties-copyable

Issue #269: Make plan viewer properties copyable
…ltips

- Add 3 missing columns to Query Trace Patterns grid (AvgWrites, Recommendation, QueryPattern with tooltip)
- Remove redundant SampleQueryText column (duplicate of QueryPattern)
- Create TracePatternHistoryWindow drill-down showing individual executions of a pattern over time
- Add GetTracePatternHistoryAsync with ROW_NUMBER dedup (trace events collected multiple times)
- Add hover tooltips to all query text columns across Dashboard (matching Lite behavior)
- Make DarkToolTip the implicit default so tooltips use dark theme
- Switch query text cells from single-line ellipsis to TextWrapping with MaxHeight=90
- Remove fixed RowHeight from grids with query text so rows auto-size

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…pattern-drilldown

Issue #273: Trace pattern drill-down, missing columns, query text tooltips
…harts

Both apps now collect from dm_exec_query_resource_semaphores (previously Lite
used dm_exec_query_memory_grants). Added two new per-pool charts to the Memory
Grants sub-tab in both apps: Sizing (available/granted/used MB) and Activity
(grantees/waiters/timeouts/forced grants).

Dashboard: simplified collector by removing inline OUTER APPLY delta, added
memory_grant_stats to the proper delta framework (calculate_deltas), removed
unused warning columns, added upgrade script for 1.3.0-to-2.0.0.

Lite: new DuckDB schema (v14 migration), DeltaCalculator seeding for
timeout/forced counters, new Memory Grants sub-tab with two ScottPlot charts.

Also includes waiting_tasks collector simplification.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…-grant-charts

Issue #281: Standardize memory grant stats and add charts
…ued I/O overlay

**New features (both apps):**
- Add "File I/O Throughput" sub-tab with read/write MB/s charts per file
- Restructure "File I/O" tab into "File I/O Latency" and "File I/O Throughput" sub-tabs
- Add queued I/O overlay (dashed lines) to latency charts showing OS queue wait time

**Lite-specific:**
- Switch File I/O latency charts from database-level to file-level (top 10 by activity)
- Add io_stall_queued_read/write columns to DuckDB schema (v15 migration)
- Update collector to collect queued stall data from sys.dm_io_virtual_file_stats
- Use DuckDB LAG() window function for throughput MB/s interval calculation

**Dashboard-specific:**
- Fix double-brace interpolation bug in GetFileIoThroughputTimeSeriesAsync
  ({{dbFilter}}/{{dateFilter}} produced literal text instead of interpolating variables)

**CI fix:**
- Update 50_configuration_issues_analyzer.sql and 97_test_procedures.sql to remove
  references to warning columns dropped from collect.memory_grant_stats in Gap 1

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… Lite

Both apps now have a "Current Waits" tab next to the Blocking/Deadlock Trends
tab, showing two charts from collected waiting_tasks data:
- Wait Duration by Wait Type: multi-series line chart of total wait_duration_ms
  per wait type over time (raw point-in-time values, not deltas)
- Blocked Sessions by Database: multi-series line chart of session count with
  blocking_session_id > 0 per database over time

Also aligns Lite collector with SQL Server collector from issue #281 — stops
collecting resource_description (now passed as NULL to match the trimmed-down
SQL Server collector which only populates session_id, wait_type,
wait_duration_ms, blocking_session_id, and database_name).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…nt-waits

Issue #280: Add Current Waits charts to Blocking tab
Remove collect.session_wait_stats entirely — table, collector procedure,
reporting view, schedule entries, schema metadata, CI checks, and all
references. This collector had 12 columns and zero UI in either app.

Adds cleanup DROPs to 02_create_tables.sql so existing installations
get cleaned up on upgrade (drops view, procedure, table, schedule row).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…-grant-charts

Issue #281 Gaps 1+2: Memory grant charts + File I/O throughput/latency/queued overlay
… and Lite

Add chart right-click context menu to all 21 Lite charts (Copy Image, Save Image As,
Open in New Window, Revert, Export CSV) with descriptive filenames using yyyy-MM-dd_HH-mm-ss
timestamp format. Consolidate Dashboard's duplicate SetupChartSaveMenu into the shared
TabHelpers.SetupChartContextMenu, and add context menus to the 2 Current Waits charts
that had none.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…-export

Issue #284: Standardize chart save/export filenames
…e_on

sys.databases.is_query_store_on can be out of sync with reality on Azure SQL DB,
reporting 0 when Query Store is actually enabled. Replace the filter with a per-database
check against sys.database_query_store_options.actual_state, which reflects the true
state. The EXISTS pattern handles empty views, NULL, and disabled states cleanly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…tection

Issue #287: Use database_query_store_options for QS detection
…and query store grids

Gap #6: Add 4 memory summary fields (available physical, total/available page file, memory model)
Gap #7: Add 9 procedure stats columns (min/max reads, physical reads, writes, spills, cached time)
Gap #9: Add 9 query store columns (exec type, first execution, CLR, tempdb, log bytes, plan type, force failures, compat level)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…m-gaps

Issue #281: Surface hidden columns in memory, procedure, and query store grids
…ore gaps, improve collector health logic

Query Stats: Add min/max physical reads, rows, grant KB, spills to Lite grids.
Add min/max physical reads to Dashboard query stats main grid.
Procedure Stats: Add min/max logical reads, physical reads, logical writes, spills to Lite grid.
Query Store: Wire 3 broken XAML bindings (ForceFailureCount, LastForceFailureReasonDesc, PlanForcingType),
add 6 hidden columns (CLR time, num physical IO reads, log bytes), add min memory/tempdb MB display.
Collector Health: Add consecutive failure detection to report.collection_health view —
5+ recent errors = FAILING, 3+ = WARNING, regardless of 7-day percentage.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ry-grant-charts

# Conflicts:
#	Lite/Controls/ServerTab.xaml
#	Lite/Services/LocalDataService.QueryStats.cs
…-grant-charts

Issue #281 Gap 3: Min/max extremes, Query Store gaps, collector health
The two throughput charts (FileIoReadThroughputChart, FileIoWriteThroughputChart)
were missed when wiring up custom context menus, showing ScottPlot's default menu.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…m-gaps

Fix missing chart context menu on File I/O Throughput charts
- Bump all 4 csproj versions to 2.0.0
- Add comprehensive CHANGELOG entry for 2.0.0
- Add session_wait_stats cleanup upgrade script
- Fix silent plan button failures (6 handlers across Dashboard and Lite)
- Add CPU scheduler pressure status below CPU chart
- Fix server timezone race on first tab open (fetch offset synchronously
  if background check hasn't completed yet)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix TRUNCATE TABLE using three-part name to avoid master context error
  when --reset-schedule is used (both CLI and GUI installers)
- Fix Version comparison bug: normalize to 3-part versions to avoid
  Revision=-1 vs Revision=0 mismatch breaking upgrade detection (both installers)
- Fix GUI installer upgrade detection: use AppAssemblyVersion instead of
  AppVersion (which includes +commithash suffix that breaks Version.TryParse)
- Add SQL Agent job cleanup (all 3 jobs) to Dashboard's DropMonitorDatabaseAsync
  so removing a server doesn't leave orphaned erroring jobs
- Update RemoveServerDialog text to mention Agent job removal

Tested: fresh install, v1.3.0→v2.0.0 upgrade, and idempotent re-run on sql2016

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…and-agent-cleanup

Fix installer upgrade bugs and add Agent job cleanup
The GUI installer was missing from v1.3.0 release because the publish
step produced 280 loose files but only the exe was copied to the release
zip. Without its DLLs, the exe would crash on launch.

Add PublishSingleFile, SelfContained, and related properties to match
the CLI installer csproj. Remove now-redundant flags from build.yml.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…-file

Fix GUI installer: publish as single-file self-contained exe
SQL collector was missing 14 counters that sp_PressureDetector collects
and the UI packs reference. TempDB Pressure pack only showed Forwarded
Records/sec (which isn't even a tempdb counter) because the 8 actual
tempdb counters were never collected. Also missing: Full Scans/sec,
Index Searches/sec, Page Splits/sec, Free list stalls/sec, Processes
blocked, Lock Timeouts/sec.

Remove Forwarded Records/sec from TempDB Pressure pack in both apps.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ters

Add missing perfmon counters to SQL collector, fix TempDB Pressure pack
@erikdarlingdata erikdarlingdata merged commit 3018ac8 into main Feb 26, 2026
7 checks passed
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.

2 participants