Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions Dashboard/Controls/QueryPerformanceContent.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,22 @@
</StackPanel>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding MinPhysicalReads, StringFormat='{}{0:N0}'}" ElementStyle="{StaticResource NumericCell}" Width="110">
<DataGridTextColumn.Header>
<StackPanel Orientation="Horizontal">
<Button Style="{DynamicResource ColumnFilterButtonStyle}" Tag="MinPhysicalReads" Click="QueryStatsFilter_Click" Margin="0,0,4,0"/>
<TextBlock Text="Min Phys Reads" FontWeight="Bold" VerticalAlignment="Center"/>
</StackPanel>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding MaxPhysicalReads, StringFormat='{}{0:N0}'}" ElementStyle="{StaticResource NumericCell}" Width="110">
<DataGridTextColumn.Header>
<StackPanel Orientation="Horizontal">
<Button Style="{DynamicResource ColumnFilterButtonStyle}" Tag="MaxPhysicalReads" Click="QueryStatsFilter_Click" Margin="0,0,4,0"/>
<TextBlock Text="Max Phys Reads" FontWeight="Bold" VerticalAlignment="Center"/>
</StackPanel>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding TotalLogicalWrites, StringFormat='{}{0:N0}'}" ElementStyle="{StaticResource NumericCell}" Width="100">
<DataGridTextColumn.Header>
<StackPanel Orientation="Horizontal">
Expand Down Expand Up @@ -1348,6 +1364,14 @@
</StackPanel>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding MinMemoryMb, StringFormat='{}{0:N2}'}" ElementStyle="{StaticResource NumericCell}" Width="100">
<DataGridTextColumn.Header>
<StackPanel Orientation="Horizontal">
<Button Style="{DynamicResource ColumnFilterButtonStyle}" Tag="MinMemoryMb" Click="QueryStoreFilter_Click" Margin="0,0,4,0"/>
<TextBlock Text="Min Mem (MB)" FontWeight="Bold" VerticalAlignment="Center"/>
</StackPanel>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding MaxMemoryMb, StringFormat='{}{0:N2}'}" ElementStyle="{StaticResource NumericCell}" Width="100">
<DataGridTextColumn.Header>
<StackPanel Orientation="Horizontal">
Expand All @@ -1364,6 +1388,14 @@
</StackPanel>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding MinTempdbMb, StringFormat='{}{0:N2}'}" ElementStyle="{StaticResource NumericCell}" Width="100">
<DataGridTextColumn.Header>
<StackPanel Orientation="Horizontal">
<Button Style="{DynamicResource ColumnFilterButtonStyle}" Tag="MinTempdbMb" Click="QueryStoreFilter_Click" Margin="0,0,4,0"/>
<TextBlock Text="Min TempDB (MB)" FontWeight="Bold" VerticalAlignment="Center"/>
</StackPanel>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding MaxTempdbMb, StringFormat='{}{0:N2}'}" ElementStyle="{StaticResource NumericCell}" Width="100">
<DataGridTextColumn.Header>
<StackPanel Orientation="Horizontal">
Expand Down Expand Up @@ -1404,6 +1436,62 @@
</StackPanel>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding PlanForcingType}" Width="100">
<DataGridTextColumn.Header>
<StackPanel Orientation="Horizontal">
<Button Style="{DynamicResource ColumnFilterButtonStyle}" Tag="PlanForcingType" Click="QueryStoreFilter_Click" Margin="0,0,4,0"/>
<TextBlock Text="Forcing Type" FontWeight="Bold" VerticalAlignment="Center"/>
</StackPanel>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding MinClrTimeMs, StringFormat='{}{0:N2}'}" ElementStyle="{StaticResource NumericCell}" Width="100">
<DataGridTextColumn.Header>
<StackPanel Orientation="Horizontal">
<Button Style="{DynamicResource ColumnFilterButtonStyle}" Tag="MinClrTimeMs" Click="QueryStoreFilter_Click" Margin="0,0,4,0"/>
<TextBlock Text="Min CLR (ms)" FontWeight="Bold" VerticalAlignment="Center"/>
</StackPanel>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding MaxClrTimeMs, StringFormat='{}{0:N2}'}" ElementStyle="{StaticResource NumericCell}" Width="100">
<DataGridTextColumn.Header>
<StackPanel Orientation="Horizontal">
<Button Style="{DynamicResource ColumnFilterButtonStyle}" Tag="MaxClrTimeMs" Click="QueryStoreFilter_Click" Margin="0,0,4,0"/>
<TextBlock Text="Max CLR (ms)" FontWeight="Bold" VerticalAlignment="Center"/>
</StackPanel>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding MinNumPhysicalIoReads, StringFormat='{}{0:N0}'}" ElementStyle="{StaticResource NumericCell}" Width="110">
<DataGridTextColumn.Header>
<StackPanel Orientation="Horizontal">
<Button Style="{DynamicResource ColumnFilterButtonStyle}" Tag="MinNumPhysicalIoReads" Click="QueryStoreFilter_Click" Margin="0,0,4,0"/>
<TextBlock Text="Min Phys IO Reads" FontWeight="Bold" VerticalAlignment="Center"/>
</StackPanel>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding MaxNumPhysicalIoReads, StringFormat='{}{0:N0}'}" ElementStyle="{StaticResource NumericCell}" Width="110">
<DataGridTextColumn.Header>
<StackPanel Orientation="Horizontal">
<Button Style="{DynamicResource ColumnFilterButtonStyle}" Tag="MaxNumPhysicalIoReads" Click="QueryStoreFilter_Click" Margin="0,0,4,0"/>
<TextBlock Text="Max Phys IO Reads" FontWeight="Bold" VerticalAlignment="Center"/>
</StackPanel>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding MinLogBytesUsed, StringFormat='{}{0:N0}'}" ElementStyle="{StaticResource NumericCell}" Width="100">
<DataGridTextColumn.Header>
<StackPanel Orientation="Horizontal">
<Button Style="{DynamicResource ColumnFilterButtonStyle}" Tag="MinLogBytesUsed" Click="QueryStoreFilter_Click" Margin="0,0,4,0"/>
<TextBlock Text="Min Log Bytes" FontWeight="Bold" VerticalAlignment="Center"/>
</StackPanel>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding MaxLogBytesUsed, StringFormat='{}{0:N0}'}" ElementStyle="{StaticResource NumericCell}" Width="100">
<DataGridTextColumn.Header>
<StackPanel Orientation="Horizontal">
<Button Style="{DynamicResource ColumnFilterButtonStyle}" Tag="MaxLogBytesUsed" Click="QueryStoreFilter_Click" Margin="0,0,4,0"/>
<TextBlock Text="Max Log Bytes" FontWeight="Bold" VerticalAlignment="Center"/>
</StackPanel>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding CompatibilityLevel}" ElementStyle="{StaticResource NumericCell}" Width="80">
<DataGridTextColumn.Header>
<StackPanel Orientation="Horizontal">
Expand Down
2 changes: 2 additions & 0 deletions Dashboard/Models/QueryStatsItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ public class QueryStatsItem
public long? AvgLogicalReads { get; set; }
public long? AvgLogicalWrites { get; set; }
public long? AvgPhysicalReads { get; set; }
public long? MinPhysicalReads { get; set; }
public long? MaxPhysicalReads { get; set; }
public long? AvgRows { get; set; }
public long? MinRows { get; set; }
public long? MaxRows { get; set; }
Expand Down
19 changes: 19 additions & 0 deletions Dashboard/Models/QueryStoreItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,23 @@ public class QueryStoreItem
public bool IsForcedPlan { get; set; }
public short? CompatibilityLevel { get; set; }

// Plan forcing details
public long? ForceFailureCount { get; set; }
public string? LastForceFailureReasonDesc { get; set; }
public string? PlanForcingType { get; set; }

// CLR time (pre-calculated in ms)
public double? MinClrTimeMs { get; set; }
public double? MaxClrTimeMs { get; set; }

// Physical IO reads (memory-optimized tables, SQL 2017+)
public long? MinNumPhysicalIoReads { get; set; }
public long? MaxNumPhysicalIoReads { get; set; }

// Log bytes used (SQL 2017+)
public long? MinLogBytesUsed { get; set; }
public long? MaxLogBytesUsed { get; set; }

// Handle
public string? QueryPlanHash { get; set; }

Expand All @@ -73,10 +90,12 @@ public class QueryStoreItem

// Display helpers - memory in MB (8KB pages * 8 / 1024)
public double? AvgMemoryMb => AvgMemoryPages.HasValue ? AvgMemoryPages.Value * 8.0 / 1024.0 : null;
public double? MinMemoryMb => MinMemoryPages.HasValue ? MinMemoryPages.Value * 8.0 / 1024.0 : null;
public double? MaxMemoryMb => MaxMemoryPages.HasValue ? MaxMemoryPages.Value * 8.0 / 1024.0 : null;

// Tempdb in MB
public double? AvgTempdbMb => AvgTempdbPages.HasValue ? AvgTempdbPages.Value * 8.0 / 1024.0 : null;
public double? MinTempdbMb => MinTempdbPages.HasValue ? MinTempdbPages.Value * 8.0 / 1024.0 : null;
public double? MaxTempdbMb => MaxTempdbPages.HasValue ? MaxTempdbPages.Value * 8.0 / 1024.0 : null;

// Property aliases for XAML binding compatibility
Expand Down
58 changes: 40 additions & 18 deletions Dashboard/Services/DatabaseService.QueryPerformance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -786,6 +786,8 @@ ELSE QUOTENAME(MAX(pl.schema_name)) + N'.' + QUOTENAME(MAX(pl.object_name))
avg_logical_writes = SUM(pl.total_logical_writes) / NULLIF(SUM(pl.execution_count), 0),
total_physical_reads = SUM(pl.total_physical_reads),
avg_physical_reads = SUM(pl.total_physical_reads) / NULLIF(SUM(pl.execution_count), 0),
min_physical_reads = MIN(pl.min_physical_reads),
max_physical_reads = MAX(pl.max_physical_reads),
total_rows = SUM(pl.total_rows),
avg_rows = SUM(pl.total_rows) / NULLIF(SUM(pl.execution_count), 0),
min_rows = MIN(pl.min_rows),
Expand Down Expand Up @@ -849,22 +851,24 @@ USE HINT('ENABLE_PARALLEL_PLAN_PREFERENCE')
AvgLogicalWrites = reader.IsDBNull(18) ? null : reader.GetInt64(18),
TotalPhysicalReads = reader.IsDBNull(19) ? 0 : reader.GetInt64(19),
AvgPhysicalReads = reader.IsDBNull(20) ? null : reader.GetInt64(20),
TotalRows = reader.IsDBNull(21) ? 0 : reader.GetInt64(21),
AvgRows = reader.IsDBNull(22) ? null : reader.GetInt64(22),
MinRows = reader.IsDBNull(23) ? null : reader.GetInt64(23),
MaxRows = reader.IsDBNull(24) ? null : reader.GetInt64(24),
MinDop = reader.IsDBNull(25) ? null : reader.GetInt16(25),
MaxDop = reader.IsDBNull(26) ? null : reader.GetInt16(26),
MinGrantKb = reader.IsDBNull(27) ? null : reader.GetInt64(27),
MaxGrantKb = reader.IsDBNull(28) ? null : reader.GetInt64(28),
TotalSpills = reader.IsDBNull(29) ? 0 : reader.GetInt64(29),
MinSpills = reader.IsDBNull(30) ? null : reader.GetInt64(30),
MaxSpills = reader.IsDBNull(31) ? null : reader.GetInt64(31),
QueryText = reader.IsDBNull(32) ? null : reader.GetString(32),
QueryPlanXml = reader.IsDBNull(33) ? null : reader.GetString(33),
QueryPlanHash = reader.IsDBNull(34) ? null : reader.GetString(34),
SqlHandle = reader.IsDBNull(35) ? null : reader.GetString(35),
PlanHandle = reader.IsDBNull(36) ? null : reader.GetString(36)
MinPhysicalReads = reader.IsDBNull(21) ? null : reader.GetInt64(21),
MaxPhysicalReads = reader.IsDBNull(22) ? null : reader.GetInt64(22),
TotalRows = reader.IsDBNull(23) ? 0 : reader.GetInt64(23),
AvgRows = reader.IsDBNull(24) ? null : reader.GetInt64(24),
MinRows = reader.IsDBNull(25) ? null : reader.GetInt64(25),
MaxRows = reader.IsDBNull(26) ? null : reader.GetInt64(26),
MinDop = reader.IsDBNull(27) ? null : reader.GetInt16(27),
MaxDop = reader.IsDBNull(28) ? null : reader.GetInt16(28),
MinGrantKb = reader.IsDBNull(29) ? null : reader.GetInt64(29),
MaxGrantKb = reader.IsDBNull(30) ? null : reader.GetInt64(30),
TotalSpills = reader.IsDBNull(31) ? 0 : reader.GetInt64(31),
MinSpills = reader.IsDBNull(32) ? null : reader.GetInt64(32),
MaxSpills = reader.IsDBNull(33) ? null : reader.GetInt64(33),
QueryText = reader.IsDBNull(34) ? null : reader.GetString(34),
QueryPlanXml = reader.IsDBNull(35) ? null : reader.GetString(35),
QueryPlanHash = reader.IsDBNull(36) ? null : reader.GetString(36),
SqlHandle = reader.IsDBNull(37) ? null : reader.GetString(37),
PlanHandle = reader.IsDBNull(38) ? null : reader.GetString(38)
});
}

Expand Down Expand Up @@ -1098,7 +1102,16 @@ public async Task<List<QueryStoreItem>> GetQueryStoreDataAsync(int hoursBack = 2
is_forced_plan = MAX(CONVERT(tinyint, qsd.is_forced_plan)),
compatibility_level = MAX(qsd.compatibility_level),
query_sql_text = CONVERT(nvarchar(max), MAX(qsd.query_sql_text)),
query_plan_hash = CONVERT(nvarchar(20), MAX(qsd.query_plan_hash), 1)
query_plan_hash = CONVERT(nvarchar(20), MAX(qsd.query_plan_hash), 1),
force_failure_count = SUM(qsd.force_failure_count),
last_force_failure_reason_desc = MAX(qsd.last_force_failure_reason_desc),
plan_forcing_type = MAX(qsd.plan_forcing_type),
min_clr_time_ms = MIN(qsd.min_clr_time) / 1000.0,
max_clr_time_ms = MAX(qsd.max_clr_time) / 1000.0,
min_num_physical_io_reads = MIN(qsd.min_num_physical_io_reads),
max_num_physical_io_reads = MAX(qsd.max_num_physical_io_reads),
min_log_bytes_used = MIN(qsd.min_log_bytes_used),
max_log_bytes_used = MAX(qsd.max_log_bytes_used)
FROM collect.query_store_data AS qsd
WHERE (
(@useCustomDates = 0 AND qsd.server_last_execution_time >= DATEADD(HOUR, -@hoursBack, SYSDATETIME()))
Expand Down Expand Up @@ -1172,7 +1185,16 @@ USE HINT('ENABLE_PARALLEL_PLAN_PREFERENCE')
IsForcedPlan = !reader.IsDBNull(35) && reader.GetByte(35) == 1,
CompatibilityLevel = reader.IsDBNull(36) ? null : reader.GetInt16(36),
QuerySqlText = reader.IsDBNull(37) ? null : reader.GetString(37),
QueryPlanHash = reader.IsDBNull(38) ? null : reader.GetString(38)
QueryPlanHash = reader.IsDBNull(38) ? null : reader.GetString(38),
ForceFailureCount = reader.IsDBNull(39) ? null : reader.GetInt64(39),
LastForceFailureReasonDesc = reader.IsDBNull(40) ? null : reader.GetString(40),
PlanForcingType = reader.IsDBNull(41) ? null : reader.GetString(41),
MinClrTimeMs = reader.IsDBNull(42) ? null : Convert.ToDouble(reader.GetValue(42), CultureInfo.InvariantCulture),
MaxClrTimeMs = reader.IsDBNull(43) ? null : Convert.ToDouble(reader.GetValue(43), CultureInfo.InvariantCulture),
MinNumPhysicalIoReads = reader.IsDBNull(44) ? null : reader.GetInt64(44),
MaxNumPhysicalIoReads = reader.IsDBNull(45) ? null : reader.GetInt64(45),
MinLogBytesUsed = reader.IsDBNull(46) ? null : reader.GetInt64(46),
MaxLogBytesUsed = reader.IsDBNull(47) ? null : reader.GetInt64(47)
// QueryPlanXml is fetched on-demand via GetQueryStorePlanXmlAsync
});
}
Expand Down
Loading
Loading