From ac2116a264af2107e8e513e13180561e686b6c32 Mon Sep 17 00:00:00 2001 From: Erik Darling <2136037+erikdarlingdata@users.noreply.github.com> Date: Mon, 9 Mar 2026 17:36:57 -0400 Subject: [PATCH] Fix sp_IndexCleanup column mapping and show all result set columns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary grid was mapping wrong ordinals (off by one after column 1) and only showed 6 of 29 columns. Detail grid was missing the Script column — the actual actionable DROP/CREATE INDEX output. Fixed ordinal mapping, expanded both grids to show all columns from both result sets, added Script and Definition columns with tooltips. Applied to both Dashboard and Lite. Co-Authored-By: Claude Opus 4.6 --- Dashboard/Controls/FinOpsContent.xaml | 127 +++++++++++------ Dashboard/Services/DatabaseService.FinOps.cs | 71 ++++++++-- Lite/Controls/FinOpsTab.xaml | 138 ++++++++++++------- Lite/Services/LocalDataService.FinOps.cs | 71 ++++++++-- 4 files changed, 291 insertions(+), 116 deletions(-) diff --git a/Dashboard/Controls/FinOpsContent.xaml b/Dashboard/Controls/FinOpsContent.xaml index 7303a485..79c62ed8 100644 --- a/Dashboard/Controls/FinOpsContent.xaml +++ b/Dashboard/Controls/FinOpsContent.xaml @@ -740,44 +740,80 @@ CanUserResizeColumns="True" HeadersVisibility="Column" SelectionMode="Extended" - MaxHeight="200" RowStyle="{StaticResource DefaultRowStyle}"> - - - - - + + + + + + - - - - + + - - - - + + - - - - + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -794,30 +830,37 @@ RowStyle="{StaticResource DefaultRowStyle}"> + - - - - + + + + + + + + + - + + + + - + diff --git a/Dashboard/Services/DatabaseService.FinOps.cs b/Dashboard/Services/DatabaseService.FinOps.cs index 624c4626..a13685e3 100644 --- a/Dashboard/Services/DatabaseService.FinOps.cs +++ b/Dashboard/Services/DatabaseService.FinOps.cs @@ -1256,15 +1256,39 @@ public async Task CheckSpIndexCleanupExistsAsync() { while (await reader.ReadAsync()) { - var fieldCount = reader.FieldCount; + var fc = reader.FieldCount; + string Col(int i) => fc > i && !reader.IsDBNull(i) ? reader.GetValue(i).ToString() ?? "" : ""; summaries.Add(new IndexCleanupSummary { - DatabaseName = fieldCount > 1 && !reader.IsDBNull(1) ? reader.GetValue(1).ToString() ?? "" : "", - TotalIndexes = fieldCount > 4 && !reader.IsDBNull(4) ? reader.GetValue(4).ToString() ?? "" : "", - UnusedIndexes = fieldCount > 5 && !reader.IsDBNull(5) ? reader.GetValue(5).ToString() ?? "" : "", - DuplicateIndexes = fieldCount > 6 && !reader.IsDBNull(6) ? reader.GetValue(6).ToString() ?? "" : "", - CompressibleIndexes = fieldCount > 7 && !reader.IsDBNull(7) ? reader.GetValue(7).ToString() ?? "" : "", - TotalSizeGb = fieldCount > 8 && !reader.IsDBNull(8) ? reader.GetValue(8).ToString() ?? "" : "" + Level = Col(0), + DatabaseInfo = Col(1), + SchemaName = Col(2), + TableName = Col(3), + TablesAnalyzed = Col(4), + TotalIndexes = Col(5), + RemovableIndexes = Col(6), + MergeableIndexes = Col(7), + CompressableIndexes = Col(8), + PercentRemovable = Col(9), + CurrentSizeGb = Col(10), + SizeAfterCleanupGb = Col(11), + SpaceSavedGb = Col(12), + SpaceReductionPercent = Col(13), + CompressionSavingsPotential = Col(14), + CompressionSavingsPotentialTotal = Col(15), + ComputedColumnsWithUdfs = Col(16), + CheckConstraintsWithUdfs = Col(17), + FilteredIndexesNeedingIncludes = Col(18), + TotalRows = Col(19), + ReadsBreakdown = Col(20), + Writes = Col(21), + DailyWriteOpsSaved = Col(22), + LockWaitCount = Col(23), + DailyLockWaitsSaved = Col(24), + AvgLockWaitMs = Col(25), + LatchWaitCount = Col(26), + DailyLatchWaitsSaved = Col(27), + AvgLatchWaitMs = Col(28) }); } } @@ -1457,11 +1481,34 @@ public class IndexCleanupResult public class IndexCleanupSummary { - public string DatabaseName { get; set; } = ""; + public string Level { get; set; } = ""; + public string DatabaseInfo { get; set; } = ""; + public string SchemaName { get; set; } = ""; + public string TableName { get; set; } = ""; + public string TablesAnalyzed { get; set; } = ""; public string TotalIndexes { get; set; } = ""; - public string UnusedIndexes { get; set; } = ""; - public string DuplicateIndexes { get; set; } = ""; - public string CompressibleIndexes { get; set; } = ""; - public string TotalSizeGb { get; set; } = ""; + public string RemovableIndexes { get; set; } = ""; + public string MergeableIndexes { get; set; } = ""; + public string CompressableIndexes { get; set; } = ""; + public string PercentRemovable { get; set; } = ""; + public string CurrentSizeGb { get; set; } = ""; + public string SizeAfterCleanupGb { get; set; } = ""; + public string SpaceSavedGb { get; set; } = ""; + public string SpaceReductionPercent { get; set; } = ""; + public string CompressionSavingsPotential { get; set; } = ""; + public string CompressionSavingsPotentialTotal { get; set; } = ""; + public string ComputedColumnsWithUdfs { get; set; } = ""; + public string CheckConstraintsWithUdfs { get; set; } = ""; + public string FilteredIndexesNeedingIncludes { get; set; } = ""; + public string TotalRows { get; set; } = ""; + public string ReadsBreakdown { get; set; } = ""; + public string Writes { get; set; } = ""; + public string DailyWriteOpsSaved { get; set; } = ""; + public string LockWaitCount { get; set; } = ""; + public string DailyLockWaitsSaved { get; set; } = ""; + public string AvgLockWaitMs { get; set; } = ""; + public string LatchWaitCount { get; set; } = ""; + public string DailyLatchWaitsSaved { get; set; } = ""; + public string AvgLatchWaitMs { get; set; } = ""; } } diff --git a/Lite/Controls/FinOpsTab.xaml b/Lite/Controls/FinOpsTab.xaml index cce0d611..7e55f9b9 100644 --- a/Lite/Controls/FinOpsTab.xaml +++ b/Lite/Controls/FinOpsTab.xaml @@ -725,7 +725,7 @@ - + @@ -739,41 +739,78 @@ SelectionMode="Extended" RowStyle="{StaticResource DefaultRowStyle}"> - - - - - + + + + + + - - - - + + - - - - + + - - - - + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -788,37 +825,38 @@ SelectionMode="Extended" RowStyle="{StaticResource DefaultRowStyle}"> - + + - - + + + + - - - + - - - - + + + + + + + + - + - + diff --git a/Lite/Services/LocalDataService.FinOps.cs b/Lite/Services/LocalDataService.FinOps.cs index 69fedb83..516c725a 100644 --- a/Lite/Services/LocalDataService.FinOps.cs +++ b/Lite/Services/LocalDataService.FinOps.cs @@ -1028,15 +1028,39 @@ public static async Task CheckSpIndexCleanupExistsAsync(string connectionS { while (await reader.ReadAsync()) { - var fieldCount = reader.FieldCount; + var fc = reader.FieldCount; + string Col(int i) => fc > i && !reader.IsDBNull(i) ? reader.GetValue(i).ToString() ?? "" : ""; summaries.Add(new IndexCleanupSummaryRow { - DatabaseName = fieldCount > 1 && !reader.IsDBNull(1) ? reader.GetValue(1).ToString() ?? "" : "", - TotalIndexes = fieldCount > 4 && !reader.IsDBNull(4) ? reader.GetValue(4).ToString() ?? "" : "", - UnusedIndexes = fieldCount > 5 && !reader.IsDBNull(5) ? reader.GetValue(5).ToString() ?? "" : "", - DuplicateIndexes = fieldCount > 6 && !reader.IsDBNull(6) ? reader.GetValue(6).ToString() ?? "" : "", - CompressibleIndexes = fieldCount > 7 && !reader.IsDBNull(7) ? reader.GetValue(7).ToString() ?? "" : "", - TotalSizeGb = fieldCount > 8 && !reader.IsDBNull(8) ? reader.GetValue(8).ToString() ?? "" : "" + Level = Col(0), + DatabaseInfo = Col(1), + SchemaName = Col(2), + TableName = Col(3), + TablesAnalyzed = Col(4), + TotalIndexes = Col(5), + RemovableIndexes = Col(6), + MergeableIndexes = Col(7), + CompressableIndexes = Col(8), + PercentRemovable = Col(9), + CurrentSizeGb = Col(10), + SizeAfterCleanupGb = Col(11), + SpaceSavedGb = Col(12), + SpaceReductionPercent = Col(13), + CompressionSavingsPotential = Col(14), + CompressionSavingsPotentialTotal = Col(15), + ComputedColumnsWithUdfs = Col(16), + CheckConstraintsWithUdfs = Col(17), + FilteredIndexesNeedingIncludes = Col(18), + TotalRows = Col(19), + ReadsBreakdown = Col(20), + Writes = Col(21), + DailyWriteOpsSaved = Col(22), + LockWaitCount = Col(23), + DailyLockWaitsSaved = Col(24), + AvgLockWaitMs = Col(25), + LatchWaitCount = Col(26), + DailyLatchWaitsSaved = Col(27), + AvgLatchWaitMs = Col(28) }); } } @@ -1227,10 +1251,33 @@ public class IndexCleanupResultRow public class IndexCleanupSummaryRow { - public string DatabaseName { get; set; } = ""; + public string Level { get; set; } = ""; + public string DatabaseInfo { get; set; } = ""; + public string SchemaName { get; set; } = ""; + public string TableName { get; set; } = ""; + public string TablesAnalyzed { get; set; } = ""; public string TotalIndexes { get; set; } = ""; - public string UnusedIndexes { get; set; } = ""; - public string DuplicateIndexes { get; set; } = ""; - public string CompressibleIndexes { get; set; } = ""; - public string TotalSizeGb { get; set; } = ""; + public string RemovableIndexes { get; set; } = ""; + public string MergeableIndexes { get; set; } = ""; + public string CompressableIndexes { get; set; } = ""; + public string PercentRemovable { get; set; } = ""; + public string CurrentSizeGb { get; set; } = ""; + public string SizeAfterCleanupGb { get; set; } = ""; + public string SpaceSavedGb { get; set; } = ""; + public string SpaceReductionPercent { get; set; } = ""; + public string CompressionSavingsPotential { get; set; } = ""; + public string CompressionSavingsPotentialTotal { get; set; } = ""; + public string ComputedColumnsWithUdfs { get; set; } = ""; + public string CheckConstraintsWithUdfs { get; set; } = ""; + public string FilteredIndexesNeedingIncludes { get; set; } = ""; + public string TotalRows { get; set; } = ""; + public string ReadsBreakdown { get; set; } = ""; + public string Writes { get; set; } = ""; + public string DailyWriteOpsSaved { get; set; } = ""; + public string LockWaitCount { get; set; } = ""; + public string DailyLockWaitsSaved { get; set; } = ""; + public string AvgLockWaitMs { get; set; } = ""; + public string LatchWaitCount { get; set; } = ""; + public string DailyLatchWaitsSaved { get; set; } = ""; + public string AvgLatchWaitMs { get; set; } = ""; }