diff --git a/src/PlanViewer.App/Controls/QueryStoreGridControl.axaml.cs b/src/PlanViewer.App/Controls/QueryStoreGridControl.axaml.cs index 1769992..077c394 100644 --- a/src/PlanViewer.App/Controls/QueryStoreGridControl.axaml.cs +++ b/src/PlanViewer.App/Controls/QueryStoreGridControl.axaml.cs @@ -462,9 +462,9 @@ private void OnWaitStatsCollapsedChanged(object? sender, bool collapsed) if (!collapsed && _slicerStartUtc.HasValue && _slicerEndUtc.HasValue) { - // Re-fetch wait stats when expanding - var cts = new CancellationTokenSource(); - _ = FetchWaitStatsAsync(_slicerStartUtc.Value, _slicerEndUtc.Value, cts.Token); + // Re-fetch wait stats when expanding — reuse the shared CTS + var ct = _fetchCts?.Token ?? CancellationToken.None; + _ = FetchWaitStatsAsync(_slicerStartUtc.Value, _slicerEndUtc.Value, ct); } } diff --git a/src/PlanViewer.Core/Services/QueryStoreService.cs b/src/PlanViewer.Core/Services/QueryStoreService.cs index dec2e83..aeb78f5 100644 --- a/src/PlanViewer.Core/Services/QueryStoreService.cs +++ b/src/PlanViewer.Core/Services/QueryStoreService.cs @@ -473,14 +473,13 @@ JOIN sys.query_store_runtime_stats_interval rsi return rows; } - /// - /// Per-plan wait stats aggregated for a time range, grouped by plan_id + category. - /// WaitRatio = SUM(total_query_wait_time_ms) / sum(rs.avg_duration*rs.count_executions) - /// ==> May be challenged. But at the detail level we use the plan duration use query stats. - /// So it is different from the other wait ratio calculation, which is based on the interval duration. - /// We can consider to align them in the future if needed. - /// - public static async Task> FetchPlanWaitStatsAsync( + /// + /// Per-plan wait stats aggregated for a time range, grouped by plan_id + category. + /// WaitRatio = SUM(total_query_wait_time_ms) / SUM(avg_duration * count_executions). + /// This differs from the global/hourly WTR (which divides by wall-clock interval) because + /// at plan level we measure what fraction of actual execution time was spent waiting. + /// + public static async Task> FetchPlanWaitStatsAsync( string connectionString, DateTime startUtc, DateTime endUtc, CancellationToken ct = default) {