From 16adb9ac753680bea1d2f88c5e6fe94610a9a96b Mon Sep 17 00:00:00 2001 From: Erik Darling <2136037+erikdarlingdata@users.noreply.github.com> Date: Thu, 19 Feb 2026 19:24:19 -0500 Subject: [PATCH] Add Physical Memory, SQL Server Memory, Target Memory to Memory Overview (#140) Adds total_physical_memory_mb and committed_target_memory_mb columns to collect.memory_stats table, collected from sys.dm_os_sys_memory and sys.dm_os_sys_info. Memory Overview summary panel now shows absolute GB values for Physical Memory, SQL Server Memory, Target Memory, Buffer Pool, and Plan Cache alongside percentages. Includes ALTER TABLE migration for existing installs. Co-Authored-By: Claude Opus 4.6 --- Dashboard/Controls/MemoryContent.xaml | 51 +++++++++++++++----- Dashboard/Controls/MemoryContent.xaml.cs | 23 +++++++-- Dashboard/Models/MemoryStatsItem.cs | 4 ++ Dashboard/Services/DatabaseService.Memory.cs | 8 ++- install/02_create_tables.sql | 16 ++++++ install/06_ensure_collection_table.sql | 15 +++--- install/14_collect_memory_stats.sql | 14 +++++- 7 files changed, 106 insertions(+), 25 deletions(-) diff --git a/Dashboard/Controls/MemoryContent.xaml b/Dashboard/Controls/MemoryContent.xaml index bae6cf3b..d157b62a 100644 --- a/Dashboard/Controls/MemoryContent.xaml +++ b/Dashboard/Controls/MemoryContent.xaml @@ -49,18 +49,45 @@ - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Dashboard/Controls/MemoryContent.xaml.cs b/Dashboard/Controls/MemoryContent.xaml.cs index 2ce4ee10..5ce7ee3b 100644 --- a/Dashboard/Controls/MemoryContent.xaml.cs +++ b/Dashboard/Controls/MemoryContent.xaml.cs @@ -333,6 +333,9 @@ private void UpdateMemoryStatsSummaryPanel(List dataList) { if (dataList == null || dataList.Count == 0) { + MemoryStatsPhysicalText.Text = "N/A"; + MemoryStatsSqlServerText.Text = "N/A"; + MemoryStatsTargetText.Text = "N/A"; MemoryStatsBPPercentText.Text = "N/A"; MemoryStatsPCPercentText.Text = "N/A"; MemoryStatsUtilPercentText.Text = "N/A"; @@ -344,14 +347,26 @@ private void UpdateMemoryStatsSummaryPanel(List dataList) // Use the most recent data point var latest = dataList.OrderByDescending(d => d.CollectionTime).First(); - MemoryStatsBPPercentText.Text = latest.BufferPoolPercentage.HasValue - ? $"{latest.BufferPoolPercentage:F1}%" + // Absolute GB values + MemoryStatsPhysicalText.Text = latest.TotalPhysicalMemoryMb.HasValue + ? $"{latest.TotalPhysicalMemoryMb.Value / 1024.0m:F1} GB" : "N/A"; - MemoryStatsPCPercentText.Text = latest.PlanCachePercentage.HasValue - ? $"{latest.PlanCachePercentage:F1}%" + MemoryStatsSqlServerText.Text = $"{latest.PhysicalMemoryInUseMb / 1024.0m:F1} GB"; + + MemoryStatsTargetText.Text = latest.CommittedTargetMemoryMb.HasValue + ? $"{latest.CommittedTargetMemoryMb.Value / 1024.0m:F1} GB" : "N/A"; + // Buffer Pool and Plan Cache with GB and percentage + MemoryStatsBPPercentText.Text = latest.BufferPoolPercentage.HasValue + ? $"{latest.BufferPoolMb / 1024.0m:F1} GB ({latest.BufferPoolPercentage:F1}%)" + : $"{latest.BufferPoolMb / 1024.0m:F1} GB"; + + MemoryStatsPCPercentText.Text = latest.PlanCachePercentage.HasValue + ? $"{latest.PlanCacheMb / 1024.0m:F1} GB ({latest.PlanCachePercentage:F1}%)" + : $"{latest.PlanCacheMb / 1024.0m:F1} GB"; + MemoryStatsUtilPercentText.Text = $"{latest.MemoryUtilizationPercentage}%"; // Build pressure status text diff --git a/Dashboard/Models/MemoryStatsItem.cs b/Dashboard/Models/MemoryStatsItem.cs index 45d5bb96..92a26421 100644 --- a/Dashboard/Models/MemoryStatsItem.cs +++ b/Dashboard/Models/MemoryStatsItem.cs @@ -18,6 +18,10 @@ public class MemoryStatsItem public decimal AvailablePhysicalMemoryMb { get; set; } public int MemoryUtilizationPercentage { get; set; } + // Server and target memory + public decimal? TotalPhysicalMemoryMb { get; set; } + public decimal? CommittedTargetMemoryMb { get; set; } + // Pressure warnings public bool BufferPoolPressureWarning { get; set; } public bool PlanCachePressureWarning { get; set; } diff --git a/Dashboard/Services/DatabaseService.Memory.cs b/Dashboard/Services/DatabaseService.Memory.cs index eb05205f..28a4d00e 100644 --- a/Dashboard/Services/DatabaseService.Memory.cs +++ b/Dashboard/Services/DatabaseService.Memory.cs @@ -46,7 +46,9 @@ public async Task> GetMemoryStatsAsync(int hoursBack = 24, ms.available_physical_memory_mb, ms.memory_utilization_percentage, ms.buffer_pool_pressure_warning, - ms.plan_cache_pressure_warning + ms.plan_cache_pressure_warning, + ms.total_physical_memory_mb, + ms.committed_target_memory_mb FROM collect.memory_stats AS ms {dateFilter} ORDER BY @@ -80,7 +82,9 @@ ORDER BY AvailablePhysicalMemoryMb = reader.GetDecimal(7), MemoryUtilizationPercentage = reader.GetInt32(8), BufferPoolPressureWarning = reader.GetBoolean(9), - PlanCachePressureWarning = reader.GetBoolean(10) + PlanCachePressureWarning = reader.GetBoolean(10), + TotalPhysicalMemoryMb = reader.IsDBNull(11) ? null : reader.GetDecimal(11), + CommittedTargetMemoryMb = reader.IsDBNull(12) ? null : reader.GetDecimal(12) }); } diff --git a/install/02_create_tables.sql b/install/02_create_tables.sql index e25923e3..c053fcab 100644 --- a/install/02_create_tables.sql +++ b/install/02_create_tables.sql @@ -194,6 +194,9 @@ BEGIN physical_memory_in_use_mb decimal(19,2) NOT NULL, available_physical_memory_mb decimal(19,2) NOT NULL, memory_utilization_percentage integer NOT NULL, + /*Server and target memory*/ + total_physical_memory_mb decimal(19,2) NULL, + committed_target_memory_mb decimal(19,2) NULL, /*Pressure warnings*/ buffer_pool_pressure_warning bit NOT NULL DEFAULT 0, plan_cache_pressure_warning bit NOT NULL DEFAULT 0, @@ -219,6 +222,19 @@ BEGIN PRINT 'Created collect.memory_stats table'; END; +/*Add columns for existing installs*/ +IF NOT EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'collect.memory_stats') AND name = N'total_physical_memory_mb') +BEGIN + ALTER TABLE collect.memory_stats ADD total_physical_memory_mb decimal(19,2) NULL; + PRINT 'Added total_physical_memory_mb to collect.memory_stats'; +END; + +IF NOT EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'collect.memory_stats') AND name = N'committed_target_memory_mb') +BEGIN + ALTER TABLE collect.memory_stats ADD committed_target_memory_mb decimal(19,2) NULL; + PRINT 'Added committed_target_memory_mb to collect.memory_stats'; +END; + /* 4. I/O Performance - handled by sp_PressureDetector NOTE: I/O metrics are collected by sp_PressureDetector into collect.PressureDetector_FileMetrics diff --git a/install/06_ensure_collection_table.sql b/install/06_ensure_collection_table.sql index f5e23e73..0b7a9407 100644 --- a/install/06_ensure_collection_table.sql +++ b/install/06_ensure_collection_table.sql @@ -294,6 +294,9 @@ BEGIN physical_memory_in_use_mb decimal(19,2) NOT NULL, available_physical_memory_mb decimal(19,2) NOT NULL, memory_utilization_percentage integer NOT NULL, + /*Server and target memory*/ + total_physical_memory_mb decimal(19,2) NULL, + committed_target_memory_mb decimal(19,2) NULL, /*Pressure warnings*/ buffer_pool_pressure_warning bit NOT NULL DEFAULT 0, plan_cache_pressure_warning bit NOT NULL DEFAULT 0, @@ -307,12 +310,12 @@ BEGIN ( plan_cache_mb * 100.0 / NULLIF(total_memory_mb, 0) - ), - CONSTRAINT - PK_memory_stats - PRIMARY KEY CLUSTERED - (collection_time, collection_id) - WITH + ), + CONSTRAINT + PK_memory_stats + PRIMARY KEY CLUSTERED + (collection_time, collection_id) + WITH (DATA_COMPRESSION = PAGE) ); END; diff --git a/install/14_collect_memory_stats.sql b/install/14_collect_memory_stats.sql index d0f5bd48..a1ebcde5 100644 --- a/install/14_collect_memory_stats.sql +++ b/install/14_collect_memory_stats.sql @@ -169,8 +169,15 @@ BEGIN system_memory AS ( SELECT - available_physical_memory_mb = sm.available_physical_memory_kb / 1024.0 + available_physical_memory_mb = sm.available_physical_memory_kb / 1024.0, + total_physical_memory_mb = sm.total_physical_memory_kb / 1024.0 FROM sys.dm_os_sys_memory AS sm + ), + system_info AS + ( + SELECT + committed_target_memory_mb = si.committed_target_kb / 1024.0 + FROM sys.dm_os_sys_info AS si ) INSERT INTO collect.memory_stats @@ -182,6 +189,8 @@ BEGIN physical_memory_in_use_mb, available_physical_memory_mb, memory_utilization_percentage, + total_physical_memory_mb, + committed_target_memory_mb, buffer_pool_pressure_warning, plan_cache_pressure_warning ) @@ -193,6 +202,8 @@ BEGIN physical_memory_in_use_mb = pm.physical_memory_in_use_mb, available_physical_memory_mb = sm.available_physical_memory_mb, memory_utilization_percentage = pm.memory_utilization_percentage, + total_physical_memory_mb = sm.total_physical_memory_mb, + committed_target_memory_mb = si.committed_target_memory_mb, buffer_pool_pressure_warning = CASE WHEN @previous_buffer_pool_mb IS NOT NULL @@ -210,6 +221,7 @@ BEGIN FROM memory_clerks AS mc CROSS JOIN process_memory AS pm CROSS JOIN system_memory AS sm + CROSS JOIN system_info AS si OPTION(RECOMPILE); SET @rows_collected = ROWCOUNT_BIG();