diff --git a/apps/studio/components/interfaces/QueryInsights/components/MetricsChart.tsx b/apps/studio/components/interfaces/QueryInsights/components/MetricsChart.tsx index 5ab0fbba2e5..f64b31e0bc8 100644 --- a/apps/studio/components/interfaces/QueryInsights/components/MetricsChart.tsx +++ b/apps/studio/components/interfaces/QueryInsights/components/MetricsChart.tsx @@ -88,7 +88,8 @@ export function MetricsChart({ if (metric === 'query_latency') { // Create the baseline chart data from the metrics const chartData = data.map((point) => { - const timestamp = dayjs(point.timestamp).format('HH:mm') + // Keep the original timestamp to maintain 5-minute intervals + const timestamp = point.timestamp return { timestamp, p50: point.p50, @@ -102,7 +103,7 @@ export function MetricsChart({ // Sort chart data by timestamp chartData.sort((a, b) => { - return dayjs(a.timestamp, 'HH:mm').diff(dayjs(b.timestamp, 'HH:mm')) + return dayjs(a.timestamp).diff(dayjs(b.timestamp)) }) // If we have query latency data, add it to the chart @@ -110,17 +111,32 @@ export function MetricsChart({ // Create a map of timestamps to query latency values const queryLatencyMap = new Map() queryLatencyData.forEach((point) => { - const timestamp = dayjs(point.timestamp).format('HH:mm') - queryLatencyMap.set(timestamp, point.value || 0) + queryLatencyMap.set(point.timestamp, point.value || 0) }) // Add query latency data to each chart data point - // Points without data will keep their 0 value chartData.forEach((point) => { if (queryLatencyMap.has(point.timestamp)) { point.query_latency = queryLatencyMap.get(point.timestamp)! } }) + + // Add any missing query latency points + queryLatencyData.forEach((point) => { + if (!chartData.find((d) => d.timestamp === point.timestamp)) { + chartData.push({ + timestamp: point.timestamp, + p50: 0, + p95: 0, + p99: 0, + p99_9: 0, + query_latency: point.value || 0, + }) + } + }) + + // Re-sort chart data by timestamp + chartData.sort((a, b) => dayjs(a.timestamp).diff(dayjs(b.timestamp))) } const config = { @@ -252,6 +268,7 @@ export function MetricsChart({ tickLine={false} axisLine={false} tickMargin={8} + tickFormatter={(value) => dayjs(value).format('HH:mm')} /> { return /* SQL */ ` SELECT bucket_start_time as timestamp, - SUM(rows_retrieved) as value, + SUM(rows) / 300 as value, -- Convert to per-second rate (5 mins = 300 seconds) datname as database FROM pg_stat_monitor - WHERE bucket_start_time >= '${startTime}' - AND bucket_start_time <= '${endTime}' + WHERE bucket_start_time >= '${startTime}'::timestamptz + AND bucket_start_time <= '${endTime}'::timestamptz + AND bucket_done = true -- Only include completed buckets GROUP BY bucket_start_time, datname - ORDER BY bucket_start_time ASC + ORDER BY timestamp ASC ` case 'rows_written': return /* SQL */ ` SELECT bucket_start_time as timestamp, - SUM(rows_retrieved) as value, + SUM(rows) / 300 as value, -- Convert to per-second rate (5 mins = 300 seconds) datname as database FROM pg_stat_monitor - WHERE bucket_start_time >= '${startTime}' - AND bucket_start_time <= '${endTime}' + WHERE bucket_start_time >= '${startTime}'::timestamptz + AND bucket_start_time <= '${endTime}'::timestamptz + AND bucket_done = true -- Only include completed buckets GROUP BY bucket_start_time, datname - ORDER BY bucket_start_time ASC + ORDER BY timestamp ASC ` case 'query_latency': return /* SQL */ ` @@ -83,54 +86,59 @@ const getMetricsSql = (metric: string, startTime: string, endTime: string) => { percentile_cont(0.999) WITHIN GROUP (ORDER BY mean_exec_time) as p99_9, datname as database FROM pg_stat_monitor - WHERE bucket_start_time >= '${startTime}' - AND bucket_start_time <= '${endTime}' + WHERE bucket_start_time >= '${startTime}'::timestamptz + AND bucket_start_time <= '${endTime}'::timestamptz + AND bucket_done = true -- Only include completed buckets GROUP BY bucket_start_time, datname - ORDER BY bucket_start_time ASC + ORDER BY timestamp ASC ` case 'queries_per_second': return /* SQL */ ` SELECT bucket_start_time as timestamp, - COUNT(*) as value, + COUNT(*) / 300.0 as value, -- Convert to per-second rate (5 mins = 300 seconds) datname as database FROM pg_stat_monitor - WHERE bucket_start_time >= '${startTime}' - AND bucket_start_time <= '${endTime}' + WHERE bucket_start_time >= '${startTime}'::timestamptz + AND bucket_start_time <= '${endTime}'::timestamptz + AND bucket_done = true -- Only include completed buckets GROUP BY bucket_start_time, datname - ORDER BY bucket_start_time ASC + ORDER BY timestamp ASC ` default: return /* SQL */ ` SELECT bucket_start_time as timestamp, - SUM(rows_retrieved) as value, + SUM(rows) / 300 as value, -- Convert to per-second rate (5 mins = 300 seconds) datname as database FROM pg_stat_monitor - WHERE bucket_start_time >= '${startTime}' - AND bucket_start_time <= '${endTime}' + WHERE bucket_start_time >= '${startTime}'::timestamptz + AND bucket_start_time <= '${endTime}'::timestamptz + AND bucket_done = true -- Only include completed buckets GROUP BY bucket_start_time, datname - ORDER BY bucket_start_time ASC + ORDER BY timestamp ASC ` } } const getQueriesSql = (startTime: string, endTime: string) => /* SQL */ ` - SELECT + SELECT queryid as query_id, - query, + COALESCE(MAX(top_query), MAX(query)) as query, SUM(total_exec_time) as total_time, SUM(calls) as calls, - SUM(rows_retrieved) as rows, + SUM(rows) as rows, SUM(shared_blks_read) as shared_blks_read, SUM(shared_blks_hit) as shared_blks_hit, - AVG(mean_exec_time) as mean_exec_time, - datname as database, - MAX(bucket_start_time) as timestamp + SUM(total_exec_time) / NULLIF(SUM(calls), 0) as mean_exec_time, + STRING_AGG(DISTINCT datname, ', ') as database, + MAX(bucket_start_time) as timestamp, + MAX(get_cmd_type(cmd_type)) as cmd_type_text FROM pg_stat_monitor WHERE bucket_start_time >= '${startTime}' AND bucket_start_time <= '${endTime}' - GROUP BY queryid, query, datname + AND bucket_done = true -- Only include completed buckets + GROUP BY queryid ORDER BY SUM(calls) DESC LIMIT 100 ` diff --git a/apps/studio/data/query-insights/single-query-latency-query.ts b/apps/studio/data/query-insights/single-query-latency-query.ts index 6f6a6a2b3ca..4313a7d1d7d 100644 --- a/apps/studio/data/query-insights/single-query-latency-query.ts +++ b/apps/studio/data/query-insights/single-query-latency-query.ts @@ -20,12 +20,14 @@ const getSingleQueryLatencySql = ( SELECT bucket_start_time as timestamp, mean_exec_time as value, + calls, datname as database FROM pg_stat_monitor - WHERE queryid = '${queryId}' - AND bucket_start_time >= '${startTime}' - AND bucket_start_time <= '${endTime}' - ORDER BY bucket_start_time ASC + WHERE bucket_start_time >= '${startTime}'::timestamptz + AND bucket_start_time <= '${endTime}'::timestamptz + AND bucket_done = true -- Only include completed buckets + AND queryid = ${queryId}::bigint + ORDER BY timestamp ASC ` export function useSingleQueryLatency( @@ -46,6 +48,7 @@ export function useSingleQueryLatency( sql: getSingleQueryLatencySql(queryId, startTime, endTime), }) + console.log('Chart data points:', result) return result as QueryInsightsMetric[] }, enabled: !!queryId && !!projectRef,