From 65abe7bb7ccd5b3caf607a19001033e324515125 Mon Sep 17 00:00:00 2001 From: Pavlo Golub Date: Thu, 28 Aug 2025 18:33:36 +0200 Subject: [PATCH 1/8] [+] add "4. Query Performance Analysis" dashboard Add enhanced dashboard with table and graph panels. --- .../v12/4-query-performance-analysis.json | 1234 +++++++++++++++++ 1 file changed, 1234 insertions(+) create mode 100644 grafana/postgres/v12/4-query-performance-analysis.json diff --git a/grafana/postgres/v12/4-query-performance-analysis.json b/grafana/postgres/v12/4-query-performance-analysis.json new file mode 100644 index 0000000000..82e7a73437 --- /dev/null +++ b/grafana/postgres/v12/4-query-performance-analysis.json @@ -0,0 +1,1234 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "Enhanced PostgreSQL statement analysis dashboard with comprehensive table view and visual analytics", + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": null, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 1, + "panels": [], + "title": "Comprehensive Query Analysis Table (pg_stat_statements)", + "type": "row" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "description": "Comprehensive query performance analysis from pg_stat_statements.\n\n**Column Guide:**\n- **Query ID** - Internal PostgreSQL query identifier (click to drill down)\n- **Total Runtime** - Total cumulative execution time\n- **Avg Runtime** - Average execution time per call\n- **Plan Time** - Total time spent planning queries\n- **Avg Plan Time** - Average planning time per call\n- **Calls** - Number of times executed\n- **Rows** - Total rows retrieved/affected\n- **Avg Rows** - Average rows per execution\n- **Shared Hit (MB)** - Buffer cache hits - data found in memory (higher is better)\n- **Shared Read (MB)** - Data read from disk into shared buffers (cache misses)\n- **Shared Written (MB)** - Data written from shared buffers to disk\n- **Temp Read (MB)** - Data read from temporary files (indicates memory pressure)\n- **Temp Written (MB)** - Data written to temporary files during large operations\n- **IO Time** - Time spent on disk I/O operations (requires track_io_timing)\n- **% DB Total** - Percentage of total database execution time\n- **Users** - Database roles that executed this query\n- **Query** - Normalized SQL text with constants replaced by placeholders", + "fieldConfig": { + "defaults": { + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Time" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "queryid" + }, + "properties": [ + { + "id": "displayName", + "value": "Query ID" + }, + { + "id": "unit", + "value": "string" + }, + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Opens 'Single query details' dashboard for that queryid", + "url": "/d/single-query-details?orgId=1&var-dbname=${dbname}&var-queryid=${__value.raw}&from=${__from}&to=${__to}" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total Runtime (ms)" + }, + "properties": [ + { + "id": "unit", + "value": "ms" + }, + { + "id": "decimals", + "value": 1 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Avg Runtime (ms)" + }, + "properties": [ + { + "id": "unit", + "value": "ms" + }, + { + "id": "decimals", + "value": 2 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Plan Time (ms)" + }, + "properties": [ + { + "id": "unit", + "value": "ms" + }, + { + "id": "decimals", + "value": 1 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Avg Plan Time (ms)" + }, + "properties": [ + { + "id": "unit", + "value": "ms" + }, + { + "id": "decimals", + "value": 2 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Calls" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 0 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Rows" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 0 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Avg Rows" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 1 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Shared Hit (MB)" + }, + "properties": [ + { + "id": "unit", + "value": "decmbytes" + }, + { + "id": "decimals", + "value": 1 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Shared Read (MB)" + }, + "properties": [ + { + "id": "unit", + "value": "decmbytes" + }, + { + "id": "decimals", + "value": 1 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Shared Written (MB)" + }, + "properties": [ + { + "id": "unit", + "value": "decmbytes" + }, + { + "id": "decimals", + "value": 1 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Temp Read (MB)" + }, + "properties": [ + { + "id": "unit", + "value": "decmbytes" + }, + { + "id": "decimals", + "value": 1 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Temp Written (MB)" + }, + "properties": [ + { + "id": "unit", + "value": "decmbytes" + }, + { + "id": "decimals", + "value": 1 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "IO Time (ms)" + }, + "properties": [ + { + "id": "unit", + "value": "ms" + }, + { + "id": "decimals", + "value": 0 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "% DB Total" + }, + "properties": [ + { + "id": "unit", + "value": "percent" + }, + { + "id": "decimals", + "value": 1 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Query ID" + }, + "properties": [ + { + "id": "custom.width", + "value": 229 + } + ] + } + ] + }, + "gridPos": { + "h": 12, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 2, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "format": "table", + "rawQuery": true, + "rawSql": "-- Enhanced comprehensive query analysis (Fast mode)\nWITH query_stats AS (\n select\n tag_data->>'queryid' as queryid,\n max((data->>'total_time')::numeric) - min((data->>'total_time')::numeric) as total_runtime,\n (max((data->>'total_time')::numeric) - min((data->>'total_time')::numeric)) / nullif(max((data->>'calls')::int8) - min((data->>'calls')::int8), 0) as avg_runtime,\n max((data->>'total_plan_time')::numeric) - min((data->>'total_plan_time')::numeric) as plan_time,\n (max((data->>'total_plan_time')::numeric) - min((data->>'total_plan_time')::numeric)) / nullif(max((data->>'calls')::int8) - min((data->>'calls')::int8), 0) as avg_plan_time,\n max((data->>'calls')::int8) - min((data->>'calls')::int8) as calls,\n max((data->>'rows')::int8) - min((data->>'rows')::int8) as rows,\n (max((data->>'rows')::int8) - min((data->>'rows')::int8))::numeric / nullif(max((data->>'calls')::int8) - min((data->>'calls')::int8), 0) as avg_rows,\n (max((data->>'shared_blks_hit')::int8) - min((data->>'shared_blks_hit')::int8)) * 8192 / 1024.0 / 1024.0 as shared_hit_mb,\n (max((data->>'shared_blks_read')::int8) - min((data->>'shared_blks_read')::int8)) * 8192 / 1024.0 / 1024.0 as shared_read_mb,\n (max((data->>'shared_blks_written')::int8) - min((data->>'shared_blks_written')::int8)) * 8192 / 1024.0 / 1024.0 as shared_written_mb,\n (max((data->>'temp_blks_read')::int8) - min((data->>'temp_blks_read')::int8)) * 8192 / 1024.0 / 1024.0 as temp_read_mb,\n (max((data->>'temp_blks_written')::int8) - min((data->>'temp_blks_written')::int8)) * 8192 / 1024.0 / 1024.0 as temp_written_mb,\n (max((data->>'blk_read_time')::numeric) - min((data->>'blk_read_time')::numeric)) + \n (max((data->>'blk_write_time')::numeric) - min((data->>'blk_write_time')::numeric)) as io_time,\n case when length(tag_data->>'query') > 150 then (tag_data->>'query')::varchar(150) || '...' else tag_data->>'query' end as query\n from stat_statements\n where dbname = '$dbname'\n and $__timeFilter(time)\n and case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n group by tag_data->>'queryid', tag_data->>'query'\n having max((data->>'calls')::int8) - min((data->>'calls')::int8) > 0\n),\nwith_percentages AS (\n select \n *,\n 100 * total_runtime / nullif((select sum(total_runtime) from query_stats), 0) as pct_db_total\n from query_stats\n)\nselect\n queryid,\n total_runtime::int8 as \"Total Runtime (ms)\",\n avg_runtime::numeric(10,2) as \"Avg Runtime (ms)\",\n plan_time::int8 as \"Plan Time (ms)\",\n avg_plan_time::numeric(10,2) as \"Avg Plan Time (ms)\",\n calls as \"Calls\",\n rows as \"Rows\",\n avg_rows::numeric(10,1) as \"Avg Rows\",\n shared_hit_mb::numeric(10,1) as \"Shared Hit (MB)\",\n shared_read_mb::numeric(10,1) as \"Shared Read (MB)\",\n shared_written_mb::numeric(10,1) as \"Shared Written (MB)\",\n temp_read_mb::numeric(10,1) as \"Temp Read (MB)\",\n temp_written_mb::numeric(10,1) as \"Temp Written (MB)\",\n io_time::numeric(10,1) as \"IO Time (ms)\",\n pct_db_total::numeric(5,1) as \"% DB Total\",\n (select data->>'users' from stat_statements where $__timeFilter(time) and dbname = '$dbname' and tag_data->>'queryid' = with_percentages.queryid order by time desc limit 1) as \"Users\",\n query as \"Query\"\nfrom with_percentages\norder by total_runtime desc nulls last\nlimit $top", + "refId": "A" + } + ], + "title": "Enhanced Query Performance Analysis Table", + "type": "table" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 13 + }, + "id": 3, + "panels": [], + "title": "Top $top queries visual analysis (pg_stat_statements)", + "type": "row" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "vis": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 14 + }, + "id": 4, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "format": "time_series", + "rawQuery": true, + "rawSql": "-- Top queries by calls over time\nWITH query_calls AS (\n select \n time,\n tag_data->>'queryid' as queryid,\n (data->>'calls')::int8 as calls\n from stat_statements \n where dbname = '$dbname'\n and $__timeFilter(time)\n and case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n),\ntop_queries AS (\n select queryid\n from query_calls\n group by queryid\n order by max(calls) - min(calls) desc\n limit $top\n)\nselect \n time as \"time\",\n calls,\n queryid as metric\nfrom query_calls\nwhere queryid in (select queryid from top_queries)\norder by time", + "refId": "A" + } + ], + "title": "Top $top statements by calls over time", + "type": "timeseries" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "vis": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 22 + }, + "id": 5, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "format": "time_series", + "rawQuery": true, + "rawSql": "-- Top queries by total execution time over time\nWITH query_runtime AS (\n select \n time,\n tag_data->>'queryid' as queryid,\n (data->>'total_time')::numeric as total_time\n from stat_statements \n where dbname = '$dbname'\n and $__timeFilter(time)\n and case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n),\ntop_queries AS (\n select queryid\n from query_runtime\n group by queryid\n order by max(total_time) - min(total_time) desc\n limit $top\n)\nselect \n time as \"time\",\n total_time,\n queryid as metric\nfrom query_runtime\nwhere queryid in (select queryid from top_queries)\norder by time", + "refId": "A" + } + ], + "title": "Top $top statements by execution time", + "type": "timeseries" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "vis": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 22 + }, + "id": 6, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "desc" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "format": "time_series", + "rawQuery": true, + "rawSql": "-- Top queries by rows over time\nWITH query_rows AS (\n select \n time,\n tag_data->>'queryid' as queryid,\n (data->>'rows')::int8 as rows\n from stat_statements \n where dbname = '$dbname'\n and $__timeFilter(time)\n and case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n),\ntop_queries AS (\n select queryid\n from query_rows\n group by queryid\n order by max(rows) - min(rows) desc\n limit $top\n)\nselect \n time as \"time\",\n rows,\n queryid as metric\nfrom query_rows\nwhere queryid in (select queryid from top_queries)\norder by time", + "refId": "A" + } + ], + "title": "Top $top statements by rows", + "type": "timeseries" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "vis": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decmbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 30 + }, + "id": 7, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "format": "time_series", + "rawQuery": true, + "rawSql": "-- Top queries by shared blocks hit over time\nWITH query_shared_hit AS (\n select \n time,\n tag_data->>'queryid' as queryid,\n (data->>'shared_blks_hit')::int8 * 8192 / 1024.0 / 1024.0 as shared_hit_mb\n from stat_statements \n where dbname = '$dbname'\n and $__timeFilter(time)\n and case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n),\ntop_queries AS (\n select queryid\n from query_shared_hit\n group by queryid\n order by max(shared_hit_mb) - min(shared_hit_mb) desc\n limit $top\n)\nselect \n time as \"time\",\n shared_hit_mb,\n queryid as metric\nfrom query_shared_hit\nwhere queryid in (select queryid from top_queries)\norder by time", + "refId": "A" + } + ], + "title": "Top $top statements by shared_blks_hit (in MB)", + "type": "timeseries" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "vis": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decmbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 30 + }, + "id": 8, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "desc" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "format": "time_series", + "rawQuery": true, + "rawSql": "-- Top queries by shared blocks read over time\nWITH query_shared_read AS (\n select \n time,\n tag_data->>'queryid' as queryid,\n (data->>'shared_blks_read')::int8 * 8192 / 1024.0 / 1024.0 as shared_read_mb\n from stat_statements \n where dbname = '$dbname'\n and $__timeFilter(time)\n and case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n),\ntop_queries AS (\n select queryid\n from query_shared_read\n group by queryid\n order by max(shared_read_mb) - min(shared_read_mb) desc\n limit $top\n)\nselect \n time as \"time\",\n shared_read_mb,\n queryid as metric\nfrom query_shared_read\nwhere queryid in (select queryid from top_queries)\norder by time", + "refId": "A" + } + ], + "title": "Top $top statements by shared_blks_read (in MB)", + "type": "timeseries" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "vis": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decmbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 38 + }, + "id": 9, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "format": "time_series", + "rawQuery": true, + "rawSql": "-- Top queries by temp blocks read over time\nWITH query_temp_read AS (\n select \n time,\n tag_data->>'queryid' as queryid,\n (data->>'temp_blks_read')::int8 * 8192 / 1024.0 / 1024.0 as temp_read_mb\n from stat_statements \n where dbname = '$dbname'\n and $__timeFilter(time)\n and case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n),\ntop_queries AS (\n select queryid\n from query_temp_read\n group by queryid\n order by max(temp_read_mb) - min(temp_read_mb) desc\n limit $top\n)\nselect \n time as \"time\",\n temp_read_mb,\n queryid as metric\nfrom query_temp_read\nwhere queryid in (select queryid from top_queries)\nand temp_read_mb > 0\norder by time", + "refId": "A" + } + ], + "title": "Top $top statements by temp bytes read (in MB)", + "type": "timeseries" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "vis": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decmbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 38 + }, + "id": 10, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "desc" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "format": "time_series", + "rawQuery": true, + "rawSql": "-- Top queries by temp blocks written over time\nWITH query_temp_written AS (\n select \n time,\n tag_data->>'queryid' as queryid,\n (data->>'temp_blks_written')::int8 * 8192 / 1024.0 / 1024.0 as temp_written_mb\n from stat_statements \n where dbname = '$dbname'\n and $__timeFilter(time)\n and case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n),\ntop_queries AS (\n select queryid\n from query_temp_written\n group by queryid\n order by max(temp_written_mb) - min(temp_written_mb) desc\n limit $top\n)\nselect \n time as \"time\",\n temp_written_mb,\n queryid as metric\nfrom query_temp_written\nwhere queryid in (select queryid from top_queries)\nand temp_written_mb > 0\norder by time", + "refId": "A" + } + ], + "title": "Top $top statements by temp bytes written (in MB)", + "type": "timeseries" + }, + { + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 0, + "y": 46 + }, + "id": 11, + "options": { + "content": "## Fast Mode Analysis\n\nThis dashboard uses **fast mode** analysis with simple max-min calculations for optimal performance. It assumes no `pg_stat_statements` reset during the time period.\n\n**Enhanced Features:** Comprehensive query analysis with sortable table view and visual time-series charts for top-performing queries.\n\nFor more detailed analysis with reset handling, use the \"Stat Statements Analysis (Unified)\" dashboard.", + "mode": "markdown" + }, + "pluginVersion": "12.0.0", + "title": "Dashboard Information", + "transparent": true, + "type": "text" + }, + { + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 12, + "y": 46 + }, + "id": 12, + "options": { + "content": "## Brought to you by\n\n\n \"Cybertec\n", + "mode": "markdown" + }, + "pluginVersion": "12.0.0", + "title": "", + "transparent": true, + "type": "text" + } + ], + "preload": false, + "refresh": "", + "schemaVersion": 41, + "tags": [ + "pgwatch" + ], + "templating": { + "list": [ + { + "current": { + "text": "demo", + "value": "demo" + }, + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "definition": "", + "includeAll": false, + "name": "dbname", + "options": [], + "query": "SELECT DISTINCT dbname FROM admin.all_distinct_dbname_metrics WHERE metric = 'stat_statements' ORDER BY 1;", + "refresh": 1, + "regex": "", + "type": "query" + }, + { + "current": { + "text": "20", + "value": "20" + }, + "includeAll": false, + "name": "top", + "options": [ + { + "selected": false, + "text": "5", + "value": "5" + }, + { + "selected": false, + "text": "10", + "value": "10" + }, + { + "selected": false, + "text": "15", + "value": "15" + }, + { + "selected": true, + "text": "20", + "value": "20" + }, + { + "selected": false, + "text": "30", + "value": "30" + }, + { + "selected": false, + "text": "50", + "value": "50" + } + ], + "query": "5,10,15,20,30,50", + "type": "custom" + }, + { + "current": { + "text": "!pgwatch_generated", + "value": "!pgwatch_generated" + }, + "includeAll": false, + "name": "query_filter_regex", + "options": [ + { + "selected": true, + "text": "!pgwatch_generated", + "value": "!pgwatch_generated" + }, + { + "selected": false, + "text": ".*", + "value": ".*" + }, + { + "selected": false, + "text": "!SELECT", + "value": "!SELECT" + }, + { + "selected": false, + "text": "UPDATE|DELETE|INSERT", + "value": "UPDATE|DELETE|INSERT" + } + ], + "query": "!pgwatch_generated,.*,!SELECT,UPDATE|DELETE|INSERT", + "type": "custom", + "description": "Custom regex filter for queries. Use '!' prefix to exclude, e.g., '!pgwatch_generated' excludes queries containing 'pgwatch_generated'. Use regular expressions like 'SELECT|INSERT' to include only specific patterns." + } + ] + }, + "time": { + "from": "now-3h", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "4. Query Performance Analysis", + "uid": "query-performance-analysis", + "version": 1 +} From 605227492ca9ad0a3959bf73f582808552887123 Mon Sep 17 00:00:00 2001 From: Pavlo Golub Date: Thu, 28 Aug 2025 18:47:57 +0200 Subject: [PATCH 2/8] remove old stat-statements dashboards --- .../v12/stat-statements-sql-search.json | 337 ---- .../v12/stat-statements-top-fast.json | 1405 ----------------- .../v12/stat-statements-top-visual.json | 441 ------ grafana/postgres/v12/stat-statements-top.json | 1111 ------------- 4 files changed, 3294 deletions(-) delete mode 100644 grafana/postgres/v12/stat-statements-sql-search.json delete mode 100644 grafana/postgres/v12/stat-statements-top-fast.json delete mode 100644 grafana/postgres/v12/stat-statements-top-visual.json delete mode 100644 grafana/postgres/v12/stat-statements-top.json diff --git a/grafana/postgres/v12/stat-statements-sql-search.json b/grafana/postgres/v12/stat-statements-sql-search.json deleted file mode 100644 index d33f8ebbac..0000000000 --- a/grafana/postgres/v12/stat-statements-sql-search.json +++ /dev/null @@ -1,337 +0,0 @@ -{ - "annotations": { - "list": [ - { - "builtIn": 1, - "datasource": { - "type": "datasource", - "uid": "grafana" - }, - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "type": "dashboard" - } - ] - }, - "editable": true, - "fiscalYearStartMonth": 0, - "graphTooltip": 0, - "id": 5, - "links": [], - "panels": [ - { - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "description": "", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "custom": { - "align": "auto", - "cellOptions": { - "type": "auto" - }, - "inspect": false - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byRegexp", - "options": "/time/" - }, - "properties": [ - { - "id": "unit", - "value": "ms" - }, - { - "id": "decimals", - "value": 2 - }, - { - "id": "custom.align" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "calls" - }, - "properties": [ - { - "id": "unit", - "value": "short" - }, - { - "id": "custom.align" - } - ] - }, - { - "matcher": { - "id": "byRegexp", - "options": "/queryid/" - }, - "properties": [ - { - "id": "unit", - "value": "short" - }, - { - "id": "decimals", - "value": 2 - }, - { - "id": "links", - "value": [ - { - "targetBlank": true, - "title": "Go to Query Details dash", - "url": "/d/single-query-details?var-dbname=$dbname&var-queryid=$__cell" - } - ] - }, - { - "id": "custom.align" - } - ] - }, - { - "matcher": { - "id": "byRegexp", - "options": "/last_exec/" - }, - "properties": [ - { - "id": "unit", - "value": "dtdurations" - }, - { - "id": "custom.align" - } - ] - } - ] - }, - "gridPos": { - "h": 16, - "w": 24, - "x": 0, - "y": 0 - }, - "id": 2, - "options": { - "cellHeight": "sm", - "footer": { - "countRows": false, - "fields": "", - "reducer": [ - "sum" - ], - "show": false - }, - "showHeader": true - }, - "pluginVersion": "12.0.0", - "targets": [ - { - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "format": "table", - "group": [], - "metricColumn": "none", - "rawQuery": true, - "rawSql": "SELECT\n total_time, mean_time, calls as total_calls, seconds_since_last_exec, queryid, query\nFROM (\n\nSELECT\n DISTINCT ON (queryid) queryid, time, total_time, mean_time, calls, query\nFROM (\n\nSELECT\n time, (data->>'total_time')::float as total_time, (data->>'total_time')::float / (data->>'calls')::int8 as mean_time, (data->>'calls')::int8 as calls, tag_data->>'queryid' as queryid, tag_data->>'query' as query\nFROM stat_statements\nWHERE\n dbname = '$dbname'\n AND time > now() - '$calls_interval'::interval\n AND tag_data->>'query' ~* '$sql_fragment'\n AND CASE WHEN length('$sql_fragment') > 2 THEN true ELSE false END\n) x\nORDER BY queryid, time DESC, mean_time, calls, query\n\n) y\nJOIN LATERAL \n (select (extract(epoch from now() - prev.time))::int8 as seconds_since_last_exec\n from stat_statements prev\n where dbname = '$dbname' and time > now() - '$calls_interval'::interval\n and prev.time < y.time and (prev.data->>'calls')::int8 != y.calls\n order by time desc limit 1\n) z on true\n\nORDER BY total_time DESC LIMIT 100", - "refId": "A", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "column" - } - ] - ], - "timeColumn": "time", - "where": [ - { - "name": "$__timeFilter", - "params": [], - "type": "macro" - } - ] - } - ], - "title": "Matching Queries", - "transformations": [ - { - "id": "merge", - "options": { - "reducers": [] - } - } - ], - "type": "table" - }, - { - "fieldConfig": { - "defaults": {}, - "overrides": [] - }, - "gridPos": { - "h": 5, - "w": 24, - "x": 0, - "y": 16 - }, - "id": 4, - "options": { - "code": { - "language": "plaintext", - "showLineNumbers": false, - "showMiniMap": false - }, - "content": "### Brought to you by\n\n[![Cybertec – The PostgreSQL Database Company](https://www.cybertec-postgresql.com/wp-content/uploads/2025/02/cybertec-logo-white-blue.svg)](https://www.cybertec-postgresql.com/en/)\n", - "mode": "markdown" - }, - "pluginVersion": "12.0.0", - "title": "", - "transparent": true, - "type": "text" - } - ], - "preload": false, - "refresh": "", - "schemaVersion": 41, - "tags": [ - "pgwatch" - ], - "templating": { - "list": [ - { - "current": { - "text": "demo", - "value": "demo" - }, - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "definition": "SELECT DISTINCT dbname FROM admin.all_distinct_dbname_metrics WHERE metric = 'stat_statements' ORDER BY 1;", - "includeAll": false, - "name": "dbname", - "options": [], - "query": "SELECT DISTINCT dbname FROM admin.all_distinct_dbname_metrics WHERE metric = 'stat_statements' ORDER BY 1;", - "refresh": 1, - "regex": "", - "type": "query" - }, - { - "current": { - "text": "", - "value": "" - }, - "label": "SQL search fragment (case insensitive, 3 char min.)", - "name": "sql_fragment", - "options": [ - { - "selected": true, - "text": "", - "value": "" - } - ], - "query": "", - "type": "textbox" - }, - { - "auto": false, - "auto_count": 30, - "auto_min": "10s", - "current": { - "text": "12h", - "value": "12h" - }, - "label": "Having some executions within last", - "name": "calls_interval", - "options": [ - { - "selected": false, - "text": "30m", - "value": "30m" - }, - { - "selected": false, - "text": "1h", - "value": "1h" - }, - { - "selected": false, - "text": "6h", - "value": "6h" - }, - { - "selected": true, - "text": "12h", - "value": "12h" - }, - { - "selected": false, - "text": "1d", - "value": "1d" - }, - { - "selected": false, - "text": "7d", - "value": "7d" - }, - { - "selected": false, - "text": "14d", - "value": "14d" - }, - { - "selected": false, - "text": "30d", - "value": "30d" - } - ], - "query": "30m,1h,6h,12h,1d,7d,14d,30d", - "refresh": 2, - "type": "interval" - } - ] - }, - "time": { - "from": "now-12h", - "to": "now" - }, - "timepicker": {}, - "timezone": "", - "title": "Stat Statements SQL Search", - "uid": "stat-statements-sql-search", - "version": 1 -} \ No newline at end of file diff --git a/grafana/postgres/v12/stat-statements-top-fast.json b/grafana/postgres/v12/stat-statements-top-fast.json deleted file mode 100644 index efa5c9905a..0000000000 --- a/grafana/postgres/v12/stat-statements-top-fast.json +++ /dev/null @@ -1,1405 +0,0 @@ -{ - "annotations": { - "list": [ - { - "builtIn": 1, - "datasource": { - "type": "datasource", - "uid": "grafana" - }, - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "type": "dashboard" - } - ] - }, - "description": "Assumes no pg_stat_statements reset appeared in the selected time frame", - "editable": true, - "fiscalYearStartMonth": 0, - "graphTooltip": 0, - "id": 9, - "links": [], - "panels": [ - { - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "description": "", - "fieldConfig": { - "defaults": { - "custom": { - "align": "auto", - "cellOptions": { - "type": "auto" - }, - "inspect": false - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Time" - }, - "properties": [ - { - "id": "displayName", - "value": "Time" - }, - { - "id": "custom.hidden", - "value": true - }, - { - "id": "custom.align" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "queryid" - }, - "properties": [ - { - "id": "displayName", - "value": "Query ID" - }, - { - "id": "unit", - "value": "short" - }, - { - "id": "decimals", - "value": 2 - }, - { - "id": "links", - "value": [ - { - "targetBlank": true, - "title": "Opens 'Single query details' dashboard for that queryid", - "url": "/d/single-query-details?orgId=1&var-dbname=$dbname&var-queryid=$__cell&from=$__from&to=$__to" - } - ] - }, - { - "id": "custom.align" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "top" - }, - "properties": [ - { - "id": "displayName", - "value": "Total runtime" - }, - { - "id": "unit", - "value": "ms" - }, - { - "id": "decimals", - "value": 1 - }, - { - "id": "custom.align" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "query" - }, - "properties": [ - { - "id": "displayName", - "value": "Query" - }, - { - "id": "unit", - "value": "short" - }, - { - "id": "decimals", - "value": 2 - }, - { - "id": "custom.align" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "approx_pct_db_total_time" - }, - "properties": [ - { - "id": "unit", - "value": "percent" - }, - { - "id": "decimals", - "value": 1 - }, - { - "id": "custom.align" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "Avg. runtime" - }, - "properties": [ - { - "id": "unit", - "value": "ms" - }, - { - "id": "decimals", - "value": 2 - }, - { - "id": "custom.align" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "Calls" - }, - "properties": [ - { - "id": "unit", - "value": "short" - }, - { - "id": "custom.align" - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 24, - "x": 0, - "y": 0 - }, - "id": 16, - "options": { - "cellHeight": "sm", - "footer": { - "countRows": false, - "fields": "", - "reducer": [ - "sum" - ], - "show": false - }, - "showHeader": true - }, - "pluginVersion": "12.0.0", - "targets": [ - { - "alias": "ass", - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "format": "table", - "group": [], - "groupBy": [ - { - "params": [ - "$__interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "metricColumn": "none", - "orderByTime": "ASC", - "policy": "default", - "query": "SELECT top(\"spread\", \"queryid\", \"query\", $top) FROM (SELECT spread(\"total_time\") FROM \"stat_statements\" WHERE $timeFilter AND \"dbname\" = '$dbname' GROUP BY time(3650d), \"queryid\", \"query\" fill(none) ) WHERE spread > 0", - "rawQuery": true, - "rawSql": "select\n tt as top,\n tt / calls as \"Avg. runtime\",\n calls as \"Calls\",\n 100 * tt / (select sum(tt_agg) from (select tag_data->>'queryid', max((data->>'total_time')::float) - min((data->>'total_time')::float) as tt_agg from stat_statements where dbname = '$dbname' and $__timeFilter(time) group by 1 having count(*) > 1) x) as approx_pct_db_total_time,\n queryid,\n (select data->>'users' from stat_statements where $__timeFilter(time) and dbname = '$dbname' and tag_data->>'queryid' = queryid order by time desc limit 1) as \"Users\", \n case when length(query) > 250 then query::varchar(250) || '...' else query end as query\nfrom (\n\n select\n tag_data->>'queryid' as queryid, tag_data->>'query' as query,\n max((data->>'total_time')::numeric) - min((data->>'total_time')::numeric) as tt,\n max((data->>'calls')::int8) - min((data->>'calls')::int8) as calls,\n min(time) as min_time,\n max(time) as max_time\n from stat_statements\n where dbname = '$dbname'\n and $__timeFilter(time)\n and case when '$hide_pgwatch_generated' = 'yes' then not tag_data->>'query' ~* E'\\\\(extract\\\\(\\\\$\\\\d+\\\\W*from\\\\W*now\\\\(\\\\)\\\\)\\\\W?\\\\*\\\\W*\\\\$\\\\d+\\\\).*::\\\\w+\\\\W+as\\\\W+epoch_ns\\\\W*,'\n and not tag_data->>'query' ~* E'/\\\\*\\\\W*pgwatch_generated\\\\W*\\\\*/' else true end\n group by\n 1, 2\n\n) x\nwhere calls > 0 and tt > 0\norder by 1 desc nulls last\nlimit $top\n\n", - "refId": "A", - "resultFormat": "table", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [], - "timeColumn": "time", - "where": [ - { - "name": "$__timeFilter", - "params": [], - "type": "macro" - } - ] - } - ], - "title": "Top queries by total runtime", - "type": "table" - }, - { - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "description": "", - "fieldConfig": { - "defaults": { - "custom": { - "align": "auto", - "cellOptions": { - "type": "auto" - }, - "inspect": false - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Time" - }, - "properties": [ - { - "id": "displayName", - "value": "Time" - }, - { - "id": "custom.hidden", - "value": true - }, - { - "id": "custom.align" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "queryid" - }, - "properties": [ - { - "id": "displayName", - "value": "Query ID" - }, - { - "id": "unit", - "value": "short" - }, - { - "id": "decimals", - "value": 2 - }, - { - "id": "links", - "value": [ - { - "targetBlank": true, - "title": "Opens 'Single query details' dashboard for that queryid", - "url": "/d/single-query-details?orgId=1&var-dbname=$dbname&var-queryid=$__cell&from=$__from&to=$__to" - } - ] - }, - { - "id": "custom.align" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "top" - }, - "properties": [ - { - "id": "displayName", - "value": "Avg. runtime" - }, - { - "id": "unit", - "value": "ms" - }, - { - "id": "decimals", - "value": 2 - }, - { - "id": "custom.align" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "query" - }, - "properties": [ - { - "id": "displayName", - "value": "Query" - }, - { - "id": "unit", - "value": "short" - }, - { - "id": "decimals", - "value": 2 - }, - { - "id": "custom.align" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "Total time" - }, - "properties": [ - { - "id": "unit", - "value": "ms" - }, - { - "id": "decimals", - "value": 1 - }, - { - "id": "custom.align" - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 24, - "x": 0, - "y": 7 - }, - "id": 15, - "options": { - "cellHeight": "sm", - "footer": { - "countRows": false, - "fields": "", - "reducer": [ - "sum" - ], - "show": false - }, - "showHeader": true - }, - "pluginVersion": "12.0.0", - "targets": [ - { - "alias": "ass", - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "format": "table", - "group": [], - "groupBy": [ - { - "params": [ - "$__interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "metricColumn": "none", - "orderByTime": "ASC", - "policy": "default", - "query": "select top(avg, \"queryid\", \"query\", $top) AS top from (select mean(t) / mean(c) AS avg from (SELECT spread(\"total_time\") AS t, spread(\"calls\") AS c FROM \"stat_statements\" WHERE $timeFilter AND dbname = '$dbname' GROUP BY time(3650d), \"queryid\", \"query\" fill(none) ) where $timeFilter AND c > 0 group by time(3650d), \"queryid\", \"query\" )", - "rawQuery": true, - "rawSql": "select\n tt / calls as top,\n tt as \"Total time\",\n calls as \"Calls\",\n queryid,\n (select data->>'users' from stat_statements where $__timeFilter(time) and dbname = '$dbname' and tag_data->>'queryid' = queryid order by time desc limit 1) as \"Users\",\n case when length(query) > 200 then query::varchar(200) || '...' else query end as query\nfrom (\n select\n tag_data->>'queryid' as queryid, tag_data->>'query' as query,\n max((data->>'total_time')::numeric) - min((data->>'total_time')::numeric) as tt,\n max((data->>'calls')::int8) - min((data->>'calls')::int8) as calls\n from stat_statements\n where dbname = '$dbname'\n and $__timeFilter(time)\n and case when '$hide_pgwatch_generated' = 'yes' then not tag_data->>'query' ~* E'\\\\(extract\\\\(\\\\$\\\\d+\\\\W*from\\\\W*now\\\\(\\\\)\\\\)\\\\W?\\\\*\\\\W*\\\\$\\\\d+\\\\).*::\\\\w+\\\\W+as\\\\W+epoch_ns\\\\W*,'\n and not tag_data->>'query' ~* E'/\\\\*\\\\W*pgwatch_generated\\\\W*\\\\*/' else true end\n group by\n 1, 2\n) x\nwhere calls > 0 and tt > 0\norder by 1 desc nulls last\nlimit $top\n\n", - "refId": "A", - "resultFormat": "table", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [], - "timeColumn": "time", - "where": [ - { - "name": "$__timeFilter", - "params": [], - "type": "macro" - } - ] - } - ], - "title": "Top queries by avg. runtime", - "type": "table" - }, - { - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "description": "", - "fieldConfig": { - "defaults": { - "custom": { - "align": "auto", - "cellOptions": { - "type": "auto" - }, - "inspect": false - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Time" - }, - "properties": [ - { - "id": "displayName", - "value": "Time" - }, - { - "id": "custom.hidden", - "value": true - }, - { - "id": "custom.align" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "queryid" - }, - "properties": [ - { - "id": "displayName", - "value": "Query ID" - }, - { - "id": "unit", - "value": "short" - }, - { - "id": "decimals", - "value": 2 - }, - { - "id": "links", - "value": [ - { - "targetBlank": true, - "title": "Opens 'Single query details' dashboard for that queryid", - "url": "/d/single-query-details?orgId=1&var-dbname=$dbname&var-queryid=$__cell&from=$__from&to=$__to" - } - ] - }, - { - "id": "custom.align" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "top" - }, - "properties": [ - { - "id": "displayName", - "value": "Calls " - }, - { - "id": "unit", - "value": "short" - }, - { - "id": "decimals", - "value": 1 - }, - { - "id": "custom.align" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "query" - }, - "properties": [ - { - "id": "displayName", - "value": "Query" - }, - { - "id": "unit", - "value": "short" - }, - { - "id": "decimals", - "value": 2 - }, - { - "id": "custom.align" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "Total time" - }, - "properties": [ - { - "id": "unit", - "value": "ms" - }, - { - "id": "decimals", - "value": 1 - }, - { - "id": "custom.align" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "Avg. runtime" - }, - "properties": [ - { - "id": "unit", - "value": "ms" - }, - { - "id": "decimals", - "value": 2 - }, - { - "id": "custom.align" - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 24, - "x": 0, - "y": 14 - }, - "id": 14, - "options": { - "cellHeight": "sm", - "footer": { - "countRows": false, - "fields": "", - "reducer": [ - "sum" - ], - "show": false - }, - "showHeader": true - }, - "pluginVersion": "12.0.0", - "targets": [ - { - "alias": "ass", - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "format": "table", - "group": [], - "groupBy": [ - { - "params": [ - "$__interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "metricColumn": "none", - "orderByTime": "ASC", - "policy": "default", - "query": "SELECT top(\"spread\", \"queryid\", \"query\", $top) FROM (SELECT spread(\"calls\") FROM \"stat_statements\" WHERE $timeFilter AND \"dbname\" = '$dbname' GROUP BY time(3650d), \"queryid\", \"query\" fill(none) ) WHERE spread > 0", - "rawQuery": true, - "rawSql": "select\n calls as top,\n total_time as \"Total time\",\n total_time / calls as \"Avg. runtime\",\n queryid,\n (select data->>'users' from stat_statements where $__timeFilter(time) and dbname = '$dbname' and tag_data->>'queryid' = queryid order by time desc limit 1) as \"Users\", \n case when length(query) > 200 then query::varchar(200) || '...' else query end as query\nfrom (\n select\n tag_data->>'queryid' as queryid, tag_data->>'query' as query,\n max((data->>'calls')::int8) - min((data->>'calls')::int8) as calls,\n max((data->>'total_time')::numeric) - min((data->>'total_time')::numeric) as total_time\n from stat_statements\n where dbname = '$dbname'\n and $__timeFilter(time)\n and case when '$hide_pgwatch_generated' = 'yes' then not tag_data->>'query' ~* E'\\\\(extract\\\\(\\\\$\\\\d+\\\\W*from\\\\W*now\\\\(\\\\)\\\\)\\\\W?\\\\*\\\\W*\\\\$\\\\d+\\\\).*::\\\\w+\\\\W+as\\\\W+epoch_ns\\\\W*,'\n and not tag_data->>'query' ~* E'/\\\\*\\\\W*pgwatch_generated\\\\W*\\\\*/' else true end \n group by\n 1, 2\n) x\nwhere calls > 0\norder by 1 desc nulls last\nlimit $top\n\n", - "refId": "A", - "resultFormat": "table", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [], - "timeColumn": "time", - "where": [ - { - "name": "$__timeFilter", - "params": [], - "type": "macro" - } - ] - } - ], - "title": "Top queries by calls", - "type": "table" - }, - { - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "description": "total_time - blk_read_time -blk_write_time. Requires track_io_timing=on", - "fieldConfig": { - "defaults": { - "custom": { - "align": "auto", - "cellOptions": { - "type": "auto" - }, - "inspect": false - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Time" - }, - "properties": [ - { - "id": "displayName", - "value": "Time" - }, - { - "id": "custom.hidden", - "value": true - }, - { - "id": "custom.align" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "top" - }, - "properties": [ - { - "id": "displayName", - "value": "CPU time" - }, - { - "id": "unit", - "value": "ms" - }, - { - "id": "decimals", - "value": 1 - }, - { - "id": "custom.align" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "queryid" - }, - "properties": [ - { - "id": "displayName", - "value": "Query ID" - }, - { - "id": "unit", - "value": "short" - }, - { - "id": "decimals", - "value": 2 - }, - { - "id": "links", - "value": [ - { - "targetBlank": false, - "title": "Opens 'Single query details' dashboard for that queryid", - "url": "/d/single-query-details?orgId=1&var-dbname=$dbname&var-queryid=$__cell&from=$__from&to=$__to" - } - ] - }, - { - "id": "custom.align" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "query" - }, - "properties": [ - { - "id": "displayName", - "value": "Query" - }, - { - "id": "unit", - "value": "short" - }, - { - "id": "decimals", - "value": 2 - }, - { - "id": "custom.align" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "Avg. runtime" - }, - "properties": [ - { - "id": "unit", - "value": "ms" - }, - { - "id": "decimals", - "value": 2 - }, - { - "id": "custom.align" - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 24, - "x": 0, - "y": 21 - }, - "id": 13, - "options": { - "cellHeight": "sm", - "footer": { - "countRows": false, - "fields": "", - "reducer": [ - "sum" - ], - "show": false - }, - "showHeader": true - }, - "pluginVersion": "12.0.0", - "targets": [ - { - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "format": "table", - "group": [], - "groupBy": [ - { - "params": [ - "$__interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "metricColumn": "none", - "orderByTime": "ASC", - "policy": "default", - "query": "SELECT top(\"spread\", \"queryid\", \"query\", $top) FROM (SELECT spread(\"blk_read_time\") + spread(\"blk_write_time\") AS spread FROM \"stat_statements\" WHERE $timeFilter AND \"dbname\" = '$dbname' GROUP BY time(3650d), \"queryid\", \"query\" fill(none) ) WHERE spread > 0", - "rawQuery": true, - "rawSql": "select\n (tt - wt - rt)::int8 as top,\n calls as \"Calls\",\n tt / calls as \"Avg. runtime\",\n queryid,\n (select data->>'users' from stat_statements where $__timeFilter(time) and dbname = '$dbname' and tag_data->>'queryid' = queryid order by time desc limit 1) as \"Users\", \n case when length(query) > 200 then query::varchar(200) || '...' else query end as query\nfrom (\n select\n tag_data->>'queryid' as queryid, tag_data->>'query' as query,\n max((data->>'total_time')::float8) - min((data->>'total_time')::float8) as tt,\n max((data->>'blk_read_time')::float8) - min((data->>'blk_read_time')::float8) as rt,\n max((data->>'blk_write_time')::float8) - min((data->>'blk_write_time')::float8) as wt,\n max((data->>'calls')::int8) - min((data->>'calls')::int8) as calls\n from stat_statements\n where dbname = '$dbname'\n and $__timeFilter(time)\n and case when '$hide_pgwatch_generated' = 'yes' then not tag_data->>'query' ~* E'\\\\(extract\\\\(\\\\$\\\\d+\\\\W*from\\\\W*now\\\\(\\\\)\\\\)\\\\W?\\\\*\\\\W*\\\\$\\\\d+\\\\).*::\\\\w+\\\\W+as\\\\W+epoch_ns\\\\W*,'\n and not tag_data->>'query' ~* E'/\\\\*\\\\W*pgwatch_generated\\\\W*\\\\*/' else true end \n group by\n 1, 2\n) x\nwhere tt - wt - rt > 0 and calls > 0\norder by 1 desc nulls last\nlimit $top\n\n", - "refId": "A", - "resultFormat": "table", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [], - "timeColumn": "time", - "where": [ - { - "name": "$__timeFilter", - "params": [], - "type": "macro" - } - ] - } - ], - "title": "Top queries by CPU time", - "type": "table" - }, - { - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "description": "Does not include Shared Buffer activities. Same as 'By total runtime' if no direct IO was performed. Requires track_io_timing=on", - "fieldConfig": { - "defaults": {}, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 24, - "x": 0, - "y": 28 - }, - "id": 12, - "options": {}, - "targets": [ - { - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "format": "table", - "group": [], - "groupBy": [ - { - "params": [ - "$__interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "metricColumn": "none", - "orderByTime": "ASC", - "policy": "default", - "query": "SELECT top(\"spread\", \"queryid\", \"query\", $top) FROM (SELECT spread(\"blk_read_time\") + spread(\"blk_write_time\") AS spread FROM \"stat_statements\" WHERE $timeFilter AND \"dbname\" = '$dbname' GROUP BY time(3650d), \"queryid\", \"query\" fill(none) ) WHERE spread > 0", - "rawQuery": true, - "rawSql": "select\n wt + rt as top,\n tt as \"Total time\",\n queryid,\n (select data->>'users' from stat_statements where $__timeFilter(time) and dbname = '$dbname' and tag_data->>'queryid' = queryid order by time desc limit 1) as \"Users\", \n case when length(query) > 200 then query::varchar(200) || '...' else query end as query\nfrom (\n select\n tag_data->>'queryid' as queryid, max(tag_data->>'query') as query,\n max((data->>'blk_read_time')::float8) - min((data->>'blk_read_time')::float8) as rt,\n max((data->>'blk_write_time')::float8) - min((data->>'blk_write_time')::float8) as wt,\n max((data->>'total_time')::float8) - min((data->>'total_time')::float8) as tt\n from stat_statements\n where dbname = '$dbname'\n and $__timeFilter(time)\n and case when '$hide_pgwatch_generated' = 'yes' then not tag_data->>'query' ~* E'\\\\(extract\\\\(\\\\$\\\\d+\\\\W*from\\\\W*now\\\\(\\\\)\\\\)\\\\W?\\\\*\\\\W*\\\\$\\\\d+\\\\).*::\\\\w+\\\\W+as\\\\W+epoch_ns\\\\W*,'\n and not tag_data->>'query' ~* E'/\\\\*\\\\W*pgwatch_generated\\\\W*\\\\*/' else true end \n group by\n 1\n) x\nwhere rt + wt > 0.1\norder by 1 desc nulls last\nlimit $top\n\n", - "refId": "A", - "resultFormat": "table", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [], - "timeColumn": "time", - "where": [ - { - "name": "$__timeFilter", - "params": [], - "type": "macro" - } - ] - } - ], - "title": "Top queries by direct (backend) IO", - "type": "table" - }, - { - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "description": "Shared buffer + temp buffer reading / writing", - "fieldConfig": { - "defaults": {}, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 24, - "x": 0, - "y": 35 - }, - "id": 11, - "options": {}, - "targets": [ - { - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "format": "table", - "group": [], - "groupBy": [ - { - "params": [ - "$__interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "metricColumn": "none", - "orderByTime": "ASC", - "policy": "default", - "query": "SELECT top(\"spread\", \"queryid\", \"query\", $top) FROM (SELECT spread(\"blk_read_time\") + spread(\"blk_write_time\") AS spread FROM \"stat_statements\" WHERE $timeFilter AND \"dbname\" = '$dbname' GROUP BY time(3650d), \"queryid\", \"query\" fill(none) ) WHERE spread > 0", - "rawQuery": true, - "rawSql": "select\n (shared_blks_hit + shared_blks_read + shared_blks_dirtied + shared_blks_written)*8192 /*assuming default 8k block size*/ as top,\n (shared_blks_hit + shared_blks_read + shared_blks_dirtied + shared_blks_written)*8192 / calls as \"Per call\",\n calls as \"Calls\",\n total_time / calls as \"Avg. runtime\",\n queryid,\n (select data->>'users' from stat_statements where $__timeFilter(time) and dbname = '$dbname' and tag_data->>'queryid' = queryid order by time desc limit 1) as \"Users\", \n case when length(query) > 200 then query::varchar(200) || '...' else query end as query\nfrom (\n select\n tag_data->>'queryid' as queryid,\n tag_data->>'query' as query,\n max((data->>'shared_blks_hit')::int8) - min((data->>'shared_blks_hit')::int8) as shared_blks_hit,\n max((data->>'shared_blks_read')::int8) - min((data->>'shared_blks_read')::int8) as shared_blks_read,\n max((data->>'shared_blks_dirtied')::int8) - min((data->>'shared_blks_dirtied')::int8) as shared_blks_dirtied,\n max((data->>'shared_blks_written')::int8) - min((data->>'shared_blks_written')::int8) as shared_blks_written,\n max((data->>'calls')::int8) - min((data->>'calls')::int8) as calls,\n max((data->>'total_time')::float) - min((data->>'total_time')::float) as total_time\n from stat_statements\n where dbname = '$dbname'\n and $__timeFilter(time)\n and case when '$hide_pgwatch_generated' = 'yes' then not tag_data->>'query' ~* E'\\\\(extract\\\\(\\\\$\\\\d+\\\\W*from\\\\W*now\\\\(\\\\)\\\\)\\\\W?\\\\*\\\\W*\\\\$\\\\d+\\\\).*::\\\\w+\\\\W+as\\\\W+epoch_ns\\\\W*,'\n and not tag_data->>'query' ~* E'/\\\\*\\\\W*pgwatch_generated\\\\W*\\\\*/' else true end\n group by\n 1, 2\n) x\nwhere calls > 0\norder by 1 desc nulls last\nlimit $top", - "refId": "A", - "resultFormat": "table", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [], - "timeColumn": "time", - "where": [ - { - "name": "$__timeFilter", - "params": [], - "type": "macro" - } - ] - } - ], - "title": "Top by block bandwith (assuming 8K blocks)", - "type": "table" - }, - { - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "description": "Based on pg_stat_statements.temp_blks_written", - "fieldConfig": { - "defaults": {}, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 24, - "x": 0, - "y": 42 - }, - "id": 17, - "options": {}, - "targets": [ - { - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "format": "table", - "group": [], - "groupBy": [ - { - "params": [ - "$__interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "metricColumn": "none", - "orderByTime": "ASC", - "policy": "default", - "query": "SELECT top(\"spread\", \"queryid\", \"query\", $top) FROM (SELECT spread(\"blk_read_time\") + spread(\"blk_write_time\") AS spread FROM \"stat_statements\" WHERE $timeFilter AND \"dbname\" = '$dbname' GROUP BY time(3650d), \"queryid\", \"query\" fill(none) ) WHERE spread > 0", - "rawQuery": true, - "rawSql": "select\n temp_blks_written * 8192 /*assuming default 8k block size*/ as top,\n (temp_blks_read * 8192) / calls as \"Temp blocks read\",\n total_time as \"Total runtime\",\n calls as \"Calls\",\n total_time / calls as \"Avg. runtime\",\n queryid,\n (select data->>'users' from stat_statements where $__timeFilter(time) and dbname = '$dbname' and tag_data->>'queryid' = queryid order by time desc limit 1) as \"Users\", \n case when length(query) > 200 then query::varchar(200) || '...' else query end as query\nfrom (\n select\n tag_data->>'queryid' as queryid,\n tag_data->>'query' as query,\n max((data->>'temp_blks_read')::int8) - min((data->>'temp_blks_read')::int8) as temp_blks_read,\n max((data->>'temp_blks_written')::int8) - min((data->>'temp_blks_written')::int8) as temp_blks_written,\n max((data->>'calls')::int8) - min((data->>'calls')::int8) as calls,\n max((data->>'total_time')::float) - min((data->>'total_time')::float) as total_time\n from stat_statements\n where dbname = '$dbname'\n and $__timeFilter(time)\n and case when '$hide_pgwatch_generated' = 'yes' then not tag_data->>'query' ~* E'\\\\(extract\\\\(\\\\$\\\\d+\\\\W*from\\\\W*now\\\\(\\\\)\\\\)\\\\W?\\\\*\\\\W*\\\\$\\\\d+\\\\).*::\\\\w+\\\\W+as\\\\W+epoch_ns\\\\W*,'\n and not tag_data->>'query' ~* E'/\\\\*\\\\W*pgwatch_generated\\\\W*\\\\*/' else true end\n group by\n 1, 2\n) x\nwhere temp_blks_written > 0\norder by 1 desc nulls last\nlimit $top", - "refId": "A", - "resultFormat": "table", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [], - "timeColumn": "time", - "where": [ - { - "name": "$__timeFilter", - "params": [], - "type": "macro" - } - ] - } - ], - "title": "Top by temp blocks (assuming 8K blocks)", - "type": "table" - }, - { - "fieldConfig": { - "defaults": {}, - "overrides": [] - }, - "gridPos": { - "h": 3, - "w": 12, - "x": 0, - "y": 49 - }, - "id": 4, - "options": {}, - "title": "", - "transparent": true, - "type": "text" - }, - { - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "fieldConfig": { - "defaults": {}, - "overrides": [] - }, - "gridPos": { - "h": 3, - "w": 12, - "x": 12, - "y": 49 - }, - "id": 18, - "maxDataPoints": 100, - "options": {}, - "targets": [ - { - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "format": "time_series", - "group": [], - "metricColumn": "none", - "rawQuery": true, - "rawSql": "select\n0 as time,\ncoalesce ((\n\nselect 1 from (\nselect\n (data->>'xact_commit')::int8 as xact_commit,\n lag((data->>'xact_commit')::int8) over (order by time) as xact_commit_lag\nfrom\n db_stats\nwhere\n $__timeFilter(time)\n and dbname = '$dbname'\n) x\nwhere xact_commit_lag > xact_commit\nlimit 1\n\n), 0) as was_reset", - "refId": "A", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "column" - } - ] - ], - "timeColumn": "time", - "where": [ - { - "name": "$__timeFilter", - "params": [], - "type": "macro" - } - ] - } - ], - "title": "", - "transparent": true, - "type": "stat" - } - ], - "preload": false, - "refresh": "", - "schemaVersion": 41, - "tags": [ - "pgwatch" - ], - "templating": { - "list": [ - { - "current": { - "text": "demo", - "value": "demo" - }, - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "definition": "", - "includeAll": false, - "name": "dbname", - "options": [], - "query": "SELECT DISTINCT dbname FROM admin.all_distinct_dbname_metrics WHERE metric = 'stat_statements' ORDER BY 1;", - "refresh": 1, - "regex": "", - "type": "query" - }, - { - "current": { - "text": "5", - "value": "5" - }, - "includeAll": false, - "name": "top", - "options": [ - { - "selected": false, - "text": "1", - "value": "1" - }, - { - "selected": false, - "text": "3", - "value": "3" - }, - { - "selected": true, - "text": "5", - "value": "5" - }, - { - "selected": false, - "text": "10", - "value": "10" - }, - { - "selected": false, - "text": "15", - "value": "15" - }, - { - "selected": false, - "text": "20", - "value": "20" - }, - { - "selected": false, - "text": "30", - "value": "30" - }, - { - "selected": false, - "text": "40", - "value": "40" - }, - { - "selected": false, - "text": "50", - "value": "50" - } - ], - "query": "1,3,5,10,15,20,30,40,50", - "type": "custom" - }, - { - "current": { - "text": "yes", - "value": "yes" - }, - "includeAll": false, - "name": "hide_pgwatch_generated", - "options": [ - { - "selected": true, - "text": "yes", - "value": "yes" - }, - { - "selected": false, - "text": "no", - "value": "no" - } - ], - "query": "yes,no", - "type": "custom" - } - ] - }, - "time": { - "from": "now-6h", - "to": "now" - }, - "timepicker": {}, - "timezone": "browser", - "title": "Stat statements Top (Fast)", - "uid": "stat-statements-top-fast", - "version": 1 -} \ No newline at end of file diff --git a/grafana/postgres/v12/stat-statements-top-visual.json b/grafana/postgres/v12/stat-statements-top-visual.json deleted file mode 100644 index 4ca51072ae..0000000000 --- a/grafana/postgres/v12/stat-statements-top-visual.json +++ /dev/null @@ -1,441 +0,0 @@ -{ - "annotations": { - "list": [ - { - "builtIn": 1, - "datasource": { - "type": "datasource", - "uid": "grafana" - }, - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "type": "dashboard" - } - ] - }, - "editable": true, - "fiscalYearStartMonth": 0, - "graphTooltip": 0, - "id": 4, - "links": [], - "panels": [ - { - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "description": "Assumes that pg_stat_statement data has not been reset in the selected time frame. Click on the graph data links for the 'Query details' view.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 10, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "min": 0, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "short" - }, - "overrides": [] - }, - "gridPos": { - "h": 12, - "w": 24, - "x": 0, - "y": 0 - }, - "id": 2, - "options": { - "dataLinks": [ - { - "targetBlank": true, - "title": "Query details", - "url": "/d/single-query-details?$__all_variables&var-queryid=${__series.name}&${__url_time_range}" - } - ], - "legend": { - "calcs": [ - "mean", - "max" - ], - "displayMode": "table", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "hideZeros": false, - "mode": "multi", - "sort": "desc" - } - }, - "pluginVersion": "12.0.0", - "targets": [ - { - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "format": "time_series", - "group": [], - "metricColumn": "none", - "rawQuery": true, - "rawSql": "SELECT\n $__timeGroup(time, $agg_interval),\n max((data->>'calls')::int8) - min((data->>'calls')::int8) as calls,\n tag_data->>'queryid' as queryid\nFROM\n stat_statements\nWHERE\n $__timeFilter(time)\n AND dbname = '$dbname'\n AND tag_data->>'queryid' IN (\n select tag_data->>'queryid'\n from stat_statements\n where $__timeFilter(time) and dbname = '$dbname'\n group by tag_data->>'queryid'\n having max((data->>'calls')::int8) - min((data->>'calls')::int8) > 0\n order by max((data->>'calls')::int8) - min((data->>'calls')::int8) desc\n limit $top\n )\nGROUP BY 1, 3\nORDER by 1\n", - "refId": "A", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "column" - } - ] - ], - "timeColumn": "time", - "where": [ - { - "name": "$__timeFilter", - "params": [], - "type": "macro" - } - ] - } - ], - "title": "Top $top queries by calls", - "type": "timeseries" - }, - { - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "description": "Assumes that pg_stat_statement data has not been reset in the selected time frame. Click on the graph data links for the 'Query details' view.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 10, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "min": 0, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "ms" - }, - "overrides": [] - }, - "gridPos": { - "h": 12, - "w": 24, - "x": 0, - "y": 12 - }, - "id": 3, - "options": { - "dataLinks": [ - { - "targetBlank": true, - "title": "Query details", - "url": "/d/single-query-details?$__all_variables&var-queryid=${__series.name}&${__url_time_range}" - } - ], - "legend": { - "calcs": [ - "mean", - "max" - ], - "displayMode": "table", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "hideZeros": false, - "mode": "multi", - "sort": "desc" - } - }, - "pluginVersion": "12.0.0", - "targets": [ - { - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "format": "time_series", - "group": [], - "metricColumn": "none", - "rawQuery": true, - "rawSql": "SELECT\n $__timeGroup(time, $agg_interval),\n max((data->>'total_time')::float) - min((data->>'total_time')::float) as total_time,\n tag_data->>'queryid' as queryid\nFROM\n stat_statements\nWHERE\n $__timeFilter(time)\n AND dbname = '$dbname'\n AND tag_data->>'queryid' IN (\n select tag_data->>'queryid'\n from stat_statements\n where $__timeFilter(time) and dbname = '$dbname'\n group by tag_data->>'queryid'\n having max((data->>'total_time')::float) - min((data->>'total_time')::float) > 0\n order by max((data->>'total_time')::float) - min((data->>'total_time')::float) desc\n limit $top\n )\nGROUP BY 1, 3\nORDER by 1\n", - "refId": "A", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "column" - } - ] - ], - "timeColumn": "time", - "where": [ - { - "name": "$__timeFilter", - "params": [], - "type": "macro" - } - ] - } - ], - "title": "Top $top queries by total time", - "type": "timeseries" - }, - { - "fieldConfig": { - "defaults": {}, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 24 - }, - "id": 5, - "options": { - "code": { - "language": "plaintext", - "showLineNumbers": false, - "showMiniMap": false - }, - "content": "### Brought to you by\n\n[![Cybertec – The PostgreSQL Database Company](https://www.cybertec-postgresql.com/wp-content/uploads/2025/02/cybertec-logo-white-blue.svg)](https://www.cybertec-postgresql.com/en/)\n", - "mode": "markdown" - }, - "pluginVersion": "12.0.0", - "title": "", - "transparent": true, - "type": "text" - } - ], - "preload": false, - "refresh": "", - "schemaVersion": 41, - "tags": [ - "pgwatch" - ], - "templating": { - "list": [ - { - "current": { - "text": "demo", - "value": "demo" - }, - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "definition": "SELECT DISTINCT dbname FROM admin.all_distinct_dbname_metrics WHERE metric = 'stat_statements' ORDER BY 1;", - "includeAll": false, - "name": "dbname", - "options": [], - "query": "SELECT DISTINCT dbname FROM admin.all_distinct_dbname_metrics WHERE metric = 'stat_statements' ORDER BY 1;", - "refresh": 1, - "regex": "", - "type": "query" - }, - { - "auto": false, - "auto_count": 30, - "auto_min": "10s", - "current": { - "text": "15m", - "value": "15m" - }, - "name": "agg_interval", - "options": [ - { - "selected": false, - "text": "5m", - "value": "5m" - }, - { - "selected": false, - "text": "10m", - "value": "10m" - }, - { - "selected": true, - "text": "15m", - "value": "15m" - }, - { - "selected": false, - "text": "30m", - "value": "30m" - }, - { - "selected": false, - "text": "1h", - "value": "1h" - }, - { - "selected": false, - "text": "6h", - "value": "6h" - }, - { - "selected": false, - "text": "12h", - "value": "12h" - }, - { - "selected": false, - "text": "1d", - "value": "1d" - } - ], - "query": "5m,10m,15m,30m,1h,6h,12h,1d", - "refresh": 2, - "type": "interval" - }, - { - "current": { - "text": "5", - "value": "5" - }, - "includeAll": false, - "name": "top", - "options": [ - { - "selected": false, - "text": "1", - "value": "1" - }, - { - "selected": false, - "text": "3", - "value": "3" - }, - { - "selected": true, - "text": "5", - "value": "5" - }, - { - "selected": false, - "text": "7", - "value": "7" - }, - { - "selected": false, - "text": "10", - "value": "10" - }, - { - "selected": false, - "text": "15", - "value": "15" - } - ], - "query": "1,3,5,7,10,15", - "type": "custom" - } - ] - }, - "time": { - "from": "now-6h", - "to": "now" - }, - "timepicker": {}, - "timezone": "", - "title": "Stat Statements Top (Visual)", - "uid": "stat-statements-top-visual", - "version": 6 -} \ No newline at end of file diff --git a/grafana/postgres/v12/stat-statements-top.json b/grafana/postgres/v12/stat-statements-top.json deleted file mode 100644 index edb98e9d0e..0000000000 --- a/grafana/postgres/v12/stat-statements-top.json +++ /dev/null @@ -1,1111 +0,0 @@ -{ - "annotations": { - "list": [ - { - "builtIn": 1, - "datasource": { - "type": "datasource", - "uid": "grafana" - }, - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "type": "dashboard" - } - ] - }, - "editable": true, - "fiscalYearStartMonth": 0, - "graphTooltip": 0, - "id": 29, - "links": [], - "panels": [ - { - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "description": "", - "fieldConfig": { - "defaults": { - "custom": { - "align": "auto", - "cellOptions": { - "type": "auto" - }, - "inspect": false - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Time" - }, - "properties": [ - { - "id": "displayName", - "value": "Time" - }, - { - "id": "custom.hidden", - "value": true - }, - { - "id": "custom.align" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "queryid" - }, - "properties": [ - { - "id": "displayName", - "value": "Query ID" - }, - { - "id": "unit", - "value": "none" - }, - { - "id": "links", - "value": [ - { - "targetBlank": true, - "title": "Opens 'Single query details' dashboard for that queryid", - "url": "/d/single-query-details?orgId=1&var-dbname=$dbname&var-queryid=$__cell&from=$__from&to=$__to" - } - ] - }, - { - "id": "custom.align" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "top" - }, - "properties": [ - { - "id": "displayName", - "value": "Total runtime" - }, - { - "id": "unit", - "value": "ms" - }, - { - "id": "decimals", - "value": 1 - }, - { - "id": "custom.align" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "query" - }, - "properties": [ - { - "id": "displayName", - "value": "Query" - }, - { - "id": "unit", - "value": "short" - }, - { - "id": "decimals", - "value": 2 - }, - { - "id": "custom.align" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "approx_pct_db_total_time" - }, - "properties": [ - { - "id": "unit", - "value": "percent" - }, - { - "id": "decimals", - "value": 1 - }, - { - "id": "custom.align" - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 24, - "x": 0, - "y": 0 - }, - "id": 5, - "options": { - "cellHeight": "sm", - "footer": { - "countRows": false, - "fields": "", - "reducer": [ - "sum" - ], - "show": false - }, - "showHeader": true - }, - "pluginVersion": "12.0.0", - "targets": [ - { - "alias": "ass", - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "format": "table", - "group": [], - "groupBy": [ - { - "params": [ - "$__interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "metricColumn": "none", - "orderByTime": "ASC", - "policy": "default", - "rawQuery": true, - "rawSql": "select\n top,\n approx_pct_db_total_time,\n queryid,\n (select data->>'users' from stat_statements where $__timeFilter(time) and dbname = '$dbname' and tag_data->>'queryid' = queryid order by time desc limit 1) as \"Users\",\n query\nfrom (\nselect\n (sum(tt - tt_lag))::int8 as top,\n round(((sum(tt - tt_lag))::int8 / total::numeric)*100, 1) as approx_pct_db_total_time,\n queryid,\n case when length(query) > 250 then query::varchar(250) || '...' else query end as query\nfrom (\nselect\n *,\n sum(tt - tt_lag) over() as total\nfrom (\n select\n tag_data->>'queryid' as queryid, tag_data->>'query' as query, data->>'users' as users,\n (data->>'total_time')::float8 as tt, lag((data->>'total_time')::float8) over w as tt_lag,\n time\n from stat_statements\n where dbname = '$dbname'\n and $__timeFilter(time)\n and case when '$hide_pgwatch_generated' = 'yes' then not tag_data->>'query' ~* E'\\\\(extract\\\\(\\\\$\\\\d+\\\\W*from\\\\W*now\\\\(\\\\)\\\\)\\\\W?\\\\*\\\\W*\\\\$\\\\d+\\\\).*::\\\\w+\\\\W+as\\\\W+epoch_ns\\\\W*,'\n and not tag_data->>'query' ~* E'/\\\\*\\\\W*pgwatch_generated\\\\W*\\\\*/' else true end\n window w as (partition by tag_data->>'queryid' order by time)\n) x\nwhere tt >= tt_lag\n) y\ngroup by total,queryid,query\nhaving sum(tt - tt_lag) > 0\norder by 1 desc nulls last\nlimit $top\n) z\norder by 1 desc nulls last", - "refId": "A", - "resultFormat": "table", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [], - "timeColumn": "time", - "where": [ - { - "name": "$__timeFilter", - "params": [], - "type": "macro" - } - ] - } - ], - "title": "Top queries by total runtime", - "type": "table" - }, - { - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "description": "", - "fieldConfig": { - "defaults": { - "custom": { - "align": "auto", - "cellOptions": { - "type": "auto" - }, - "inspect": false - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Time" - }, - "properties": [ - { - "id": "displayName", - "value": "Time" - }, - { - "id": "custom.hidden", - "value": true - }, - { - "id": "custom.align" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "queryid" - }, - "properties": [ - { - "id": "displayName", - "value": "Query ID" - }, - { - "id": "unit", - "value": "none" - }, - { - "id": "links", - "value": [ - { - "targetBlank": true, - "title": "Opens 'Single query details' dashboard for that queryid", - "url": "/d/single-query-details?orgId=1&var-dbname=$dbname&var-queryid=$__cell&from=$__from&to=$__to" - } - ] - }, - { - "id": "custom.align" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "top" - }, - "properties": [ - { - "id": "displayName", - "value": "Avg. runtime" - }, - { - "id": "unit", - "value": "ms" - }, - { - "id": "decimals", - "value": 2 - }, - { - "id": "custom.align" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "query" - }, - "properties": [ - { - "id": "displayName", - "value": "Query" - }, - { - "id": "unit", - "value": "short" - }, - { - "id": "decimals", - "value": 2 - }, - { - "id": "custom.align" - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 24, - "x": 0, - "y": 7 - }, - "id": 6, - "options": { - "cellHeight": "sm", - "footer": { - "countRows": false, - "fields": "", - "reducer": [ - "sum" - ], - "show": false - }, - "showHeader": true - }, - "pluginVersion": "12.0.0", - "targets": [ - { - "alias": "ass", - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "format": "table", - "group": [], - "groupBy": [ - { - "params": [ - "$__interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "metricColumn": "none", - "orderByTime": "ASC", - "policy": "default", - "rawQuery": true, - "rawSql": "select\n top,\n queryid,\n (select data->>'users' from stat_statements where $__timeFilter(time) and dbname = '$dbname' and tag_data->>'queryid' = queryid order by time desc limit 1) as \"Users\",\n query\nfrom (\nselect\n (avg((tt - tt_lag)::numeric / (calls - calls_lag)))::int8 as top,\n queryid,\n case when length(query) > 200 then query::varchar(200) || '...' else query end as query\nfrom (\n select\n tag_data->>'queryid' as queryid, tag_data->>'query' as query, data->>'users' as users,\n (data->>'total_time')::float8 as tt, lag((data->>'total_time')::float8) over w as tt_lag,\n (data->>'calls')::int8 as calls, lag((data->>'calls')::int8) over w as calls_lag,\n time\n from stat_statements\n where dbname = '$dbname'\n and $__timeFilter(time)\n and case when '$hide_pgwatch_generated' = 'yes' then not tag_data->>'query' ~* E'\\\\(extract\\\\(\\\\$\\\\d+\\\\W*from\\\\W*now\\\\(\\\\)\\\\)\\\\W?\\\\*\\\\W*\\\\$\\\\d+\\\\).*::\\\\w+\\\\W+as\\\\W+epoch_ns\\\\W*,'\n and not tag_data->>'query' ~* E'/\\\\*\\\\W*pgwatch_generated\\\\W*\\\\*/' else true end\n window w as (partition by tag_data->>'queryid' order by time)\n) x\nwhere calls > calls_lag\ngroup by 2, 3\norder by 1 desc nulls last\nlimit $top\n) z\norder by 1 desc nulls last", - "refId": "A", - "resultFormat": "table", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [], - "timeColumn": "time", - "where": [ - { - "name": "$__timeFilter", - "params": [], - "type": "macro" - } - ] - } - ], - "title": "Top queries by avg. runtime", - "type": "table" - }, - { - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "description": "", - "fieldConfig": { - "defaults": { - "custom": { - "align": "auto", - "cellOptions": { - "type": "auto" - }, - "inspect": false - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Time" - }, - "properties": [ - { - "id": "displayName", - "value": "Time" - }, - { - "id": "custom.hidden", - "value": true - }, - { - "id": "custom.align" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "queryid" - }, - "properties": [ - { - "id": "displayName", - "value": "Query ID" - }, - { - "id": "unit", - "value": "none" - }, - { - "id": "links", - "value": [ - { - "targetBlank": true, - "title": "Opens 'Single query details' dashboard for that queryid", - "url": "/d/single-query-details?orgId=1&var-dbname=$dbname&var-queryid=$__cell&from=$__from&to=$__to" - } - ] - }, - { - "id": "custom.align" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "top" - }, - "properties": [ - { - "id": "displayName", - "value": "Calls " - }, - { - "id": "unit", - "value": "short" - }, - { - "id": "decimals", - "value": 1 - }, - { - "id": "custom.align" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "query" - }, - "properties": [ - { - "id": "displayName", - "value": "Query" - }, - { - "id": "unit", - "value": "short" - }, - { - "id": "decimals", - "value": 2 - }, - { - "id": "custom.align" - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 24, - "x": 0, - "y": 14 - }, - "id": 7, - "options": { - "cellHeight": "sm", - "footer": { - "countRows": false, - "fields": "", - "reducer": [ - "sum" - ], - "show": false - }, - "showHeader": true - }, - "pluginVersion": "12.0.0", - "targets": [ - { - "alias": "ass", - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "format": "table", - "group": [], - "groupBy": [ - { - "params": [ - "$__interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "metricColumn": "none", - "orderByTime": "ASC", - "policy": "default", - "rawQuery": true, - "rawSql": "select\n top,\n queryid,\n (select data->>'users' from stat_statements where $__timeFilter(time) and dbname = '$dbname' and tag_data->>'queryid' = queryid order by time desc limit 1) as \"Users\",\n query\nfrom (\nselect\n sum(calls - calls_lag)::int8 as top,\n queryid,\n case when length(query) > 200 then query::varchar(200) || '...' else query end as query\nfrom (\n select\n tag_data->>'queryid' as queryid, tag_data->>'query' as query, data->>'users' as users,\n (data->>'calls')::int8 as calls, lag((data->>'calls')::int8) over w as calls_lag,\n time\n from stat_statements\n where dbname = '$dbname'\n and $__timeFilter(time)\n and case when '$hide_pgwatch_generated' = 'yes' then not tag_data->>'query' ~* E'\\\\(extract\\\\(\\\\$\\\\d+\\\\W*from\\\\W*now\\\\(\\\\)\\\\)\\\\W?\\\\*\\\\W*\\\\$\\\\d+\\\\).*::\\\\w+\\\\W+as\\\\W+epoch_ns\\\\W*,'\n and not tag_data->>'query' ~* E'/\\\\*\\\\W*pgwatch_generated\\\\W*\\\\*/' else true end \n window w as (partition by tag_data->>'queryid' order by time)\n) x\nwhere calls > calls_lag\ngroup by 2, 3\norder by 1 desc nulls last\nlimit $top\n) z\norder by 1 desc nulls last", - "refId": "A", - "resultFormat": "table", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [], - "timeColumn": "time", - "where": [ - { - "name": "$__timeFilter", - "params": [], - "type": "macro" - } - ] - } - ], - "title": "Top queries by calls", - "type": "table" - }, - { - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "description": "Does not include Shared Buffer activities. Same as 'By total runtime' if no direct IO was performed. Requires track_io_timing=on", - "fieldConfig": { - "defaults": { - "custom": { - "align": "auto", - "cellOptions": { - "type": "auto" - }, - "inspect": false - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Time" - }, - "properties": [ - { - "id": "displayName", - "value": "Time" - }, - { - "id": "custom.hidden", - "value": true - }, - { - "id": "custom.align" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "top" - }, - "properties": [ - { - "id": "displayName", - "value": "IO time" - }, - { - "id": "unit", - "value": "ms" - }, - { - "id": "decimals", - "value": 1 - }, - { - "id": "custom.align" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "queryid" - }, - "properties": [ - { - "id": "displayName", - "value": "Query ID" - }, - { - "id": "unit", - "value": "none" - }, - { - "id": "links", - "value": [ - { - "targetBlank": false, - "title": "Opens 'Single query details' dashboard for that queryid", - "url": "/d/single-query-details?orgId=1&var-dbname=$dbname&var-queryid=$__cell&from=$__from&to=$__to" - } - ] - }, - { - "id": "custom.align" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "query" - }, - "properties": [ - { - "id": "displayName", - "value": "Query" - }, - { - "id": "unit", - "value": "short" - }, - { - "id": "decimals", - "value": 2 - }, - { - "id": "custom.align" - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 24, - "x": 0, - "y": 21 - }, - "id": 8, - "options": { - "cellHeight": "sm", - "footer": { - "countRows": false, - "fields": "", - "reducer": [ - "sum" - ], - "show": false - }, - "showHeader": true - }, - "pluginVersion": "12.0.0", - "targets": [ - { - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "format": "table", - "group": [], - "groupBy": [ - { - "params": [ - "$__interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "metricColumn": "none", - "orderByTime": "ASC", - "policy": "default", - "query": "SELECT top(\"spread\", \"queryid\", \"query\", $top) FROM (SELECT spread(\"blk_read_time\") + spread(\"blk_write_time\") AS spread FROM \"stat_statements\" WHERE $timeFilter AND \"dbname\" = '$dbname' GROUP BY time(3650d), \"queryid\", \"query\" fill(none) ) WHERE spread > 0", - "rawQuery": true, - "rawSql": "select\n top,\n queryid,\n (select data->>'users' from stat_statements where $__timeFilter(time) and dbname = '$dbname' and tag_data->>'queryid' = queryid order by time desc limit 1) as \"Users\",\n query\nfrom (\nselect\n sum((wt - wt_lag) + (rt - rt_lag))::int8 as top,\n queryid,\n case when length(query) > 200 then query::varchar(200) || '...' else query end as query\nfrom (\n select\n tag_data->>'queryid' as queryid, tag_data->>'query' as query, data->>'users' as users,\n (data->>'blk_read_time')::float8 as rt, lag((data->>'blk_read_time')::float8) over w as rt_lag,\n (data->>'blk_write_time')::float8 as wt, lag((data->>'blk_write_time')::float8) over w as wt_lag, \n time\n from stat_statements\n where dbname = '$dbname'\n and $__timeFilter(time)\n and case when '$hide_pgwatch_generated' = 'yes' then not tag_data->>'query' ~* E'\\\\(extract\\\\(\\\\$\\\\d+\\\\W*from\\\\W*now\\\\(\\\\)\\\\)\\\\W?\\\\*\\\\W*\\\\$\\\\d+\\\\).*::\\\\w+\\\\W+as\\\\W+epoch_ns\\\\W*,'\n and not tag_data->>'query' ~* E'/\\\\*\\\\W*pgwatch_generated\\\\W*\\\\*/' else true end \n window w as (partition by tag_data->>'queryid' order by time)\n) x\nwhere rt > rt_lag or wt > wt_lag\ngroup by 2, 3\norder by 1 desc nulls last\nlimit $top\n) z\norder by 1 desc nulls last", - "refId": "A", - "resultFormat": "table", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [], - "timeColumn": "time", - "where": [ - { - "name": "$__timeFilter", - "params": [], - "type": "macro" - } - ] - } - ], - "title": "Top queries by direct (backend) IO", - "type": "table" - }, - { - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "description": "Shared buffer + temp buffer reading / writing", - "fieldConfig": { - "defaults": { - "custom": { - "align": "auto", - "cellOptions": { - "type": "auto" - }, - "inspect": false - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 24, - "x": 0, - "y": 28 - }, - "id": 10, - "options": { - "cellHeight": "sm", - "footer": { - "countRows": false, - "fields": "", - "reducer": [ - "sum" - ], - "show": false - }, - "showHeader": true - }, - "pluginVersion": "12.0.0", - "targets": [ - { - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "format": "table", - "group": [], - "groupBy": [ - { - "params": [ - "$__interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "metricColumn": "none", - "orderByTime": "ASC", - "policy": "default", - "query": "SELECT top(\"spread\", \"queryid\", \"query\", $top) FROM (SELECT spread(\"blk_read_time\") + spread(\"blk_write_time\") AS spread FROM \"stat_statements\" WHERE $timeFilter AND \"dbname\" = '$dbname' GROUP BY time(3650d), \"queryid\", \"query\" fill(none) ) WHERE spread > 0", - "rawQuery": true, - "rawSql": "select\n top,\n queryid,\n (select data->>'users' from stat_statements where $__timeFilter(time) and dbname = '$dbname' and tag_data->>'queryid' = queryid order by time desc limit 1) as \"Users\",\n query\nfrom (\nselect\n sum(blocks_touched - blocks_touched_lag)*8192 /*assuming default 8k block size*/ as top,\n queryid,\n case when length(query) > 200 then query::varchar(200) || '...' else query end as query\nfrom (\n select\n tag_data->>'queryid' as queryid, tag_data->>'query' as query, data->>'users' as users,\n (data->>'shared_blks_hit')::int8 + (data->>'shared_blks_read')::int8 + (data->>'shared_blks_dirtied')::int8 + (data->>'shared_blks_written')::int8\n + (data->>'temp_blks_read')::int8 + (data->>'temp_blks_written')::int8 as blocks_touched,\n lag((data->>'shared_blks_hit')::int8 + (data->>'shared_blks_read')::int8 + (data->>'shared_blks_dirtied')::int8 + (data->>'shared_blks_written')::int8\n + (data->>'temp_blks_read')::int8 + (data->>'temp_blks_written')::int8) over w as blocks_touched_lag,\n time\n from stat_statements\n where dbname = '$dbname'\n and $__timeFilter(time)\n and case when '$hide_pgwatch_generated' = 'yes' then not tag_data->>'query' ~* E'\\\\(extract\\\\(\\\\$\\\\d+\\\\W*from\\\\W*now\\\\(\\\\)\\\\)\\\\W?\\\\*\\\\W*\\\\$\\\\d+\\\\).*::\\\\w+\\\\W+as\\\\W+epoch_ns\\\\W*,'\n and not tag_data->>'query' ~* E'/\\\\*\\\\W*pgwatch_generated\\\\W*\\\\*/' else true end \n window w as (partition by tag_data->>'queryid' order by time)\n) x\nwhere blocks_touched >= blocks_touched_lag\ngroup by 2, 3\nhaving sum(blocks_touched - blocks_touched_lag) > 0\norder by 1 desc nulls last\nlimit $top\n) z\norder by 1 desc nulls last", - "refId": "A", - "resultFormat": "table", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [], - "timeColumn": "time", - "where": [ - { - "name": "$__timeFilter", - "params": [], - "type": "macro" - } - ] - } - ], - "title": "Top by block bandwith (assuming 8K blocks)", - "type": "table" - }, - { - "fieldConfig": { - "defaults": {}, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 24, - "x": 0, - "y": 35 - }, - "id": 4, - "options": { - "code": { - "language": "plaintext", - "showLineNumbers": false, - "showMiniMap": false - }, - "content": "## Brought to you by\n\n\n \"Cybertec\n", - "mode": "markdown" - }, - "pluginVersion": "12.0.0", - "title": "", - "transparent": true, - "type": "text" - } - ], - "preload": false, - "refresh": "", - "schemaVersion": 41, - "tags": [ - "pgwatch" - ], - "templating": { - "list": [ - { - "current": { - "text": "demo", - "value": "demo" - }, - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "definition": "", - "includeAll": false, - "name": "dbname", - "options": [], - "query": "SELECT DISTINCT dbname FROM admin.all_distinct_dbname_metrics WHERE metric = 'stat_statements' ORDER BY 1;", - "refresh": 1, - "regex": "", - "type": "query" - }, - { - "current": { - "text": "5", - "value": "5" - }, - "includeAll": false, - "name": "top", - "options": [ - { - "selected": false, - "text": "1", - "value": "1" - }, - { - "selected": false, - "text": "3", - "value": "3" - }, - { - "selected": true, - "text": "5", - "value": "5" - }, - { - "selected": false, - "text": "10", - "value": "10" - }, - { - "selected": false, - "text": "15", - "value": "15" - }, - { - "selected": false, - "text": "20", - "value": "20" - }, - { - "selected": false, - "text": "30", - "value": "30" - }, - { - "selected": false, - "text": "40", - "value": "40" - }, - { - "selected": false, - "text": "50", - "value": "50" - } - ], - "query": "1,3,5,10,15,20,30,40,50", - "type": "custom" - }, - { - "current": { - "text": "yes", - "value": "yes" - }, - "includeAll": false, - "name": "hide_pgwatch_generated", - "options": [ - { - "selected": true, - "text": "yes", - "value": "yes" - }, - { - "selected": false, - "text": "no", - "value": "no" - } - ], - "query": "yes,no", - "type": "custom" - } - ] - }, - "time": { - "from": "now-3h", - "to": "now" - }, - "timepicker": {}, - "timezone": "browser", - "title": "Stat statements Top", - "uid": "stat-statements-top", - "version": 3 -} \ No newline at end of file From a4acac5e89b23dd10f068d06a1721733221d68c6 Mon Sep 17 00:00:00 2001 From: Pavlo Golub Date: Fri, 29 Aug 2025 12:39:18 +0200 Subject: [PATCH 3/8] remove description panel and tweak var labels --- .../v12/4-query-performance-analysis.json | 133 ++++++++++-------- 1 file changed, 78 insertions(+), 55 deletions(-) diff --git a/grafana/postgres/v12/4-query-performance-analysis.json b/grafana/postgres/v12/4-query-performance-analysis.json index 82e7a73437..49f4cce758 100644 --- a/grafana/postgres/v12/4-query-performance-analysis.json +++ b/grafana/postgres/v12/4-query-performance-analysis.json @@ -19,7 +19,7 @@ "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, - "id": null, + "id": 42, "links": [], "panels": [ { @@ -55,7 +55,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": 0 }, { "color": "red", @@ -180,6 +181,10 @@ { "id": "decimals", "value": 0 + }, + { + "id": "custom.width", + "value": 76 } ] }, @@ -196,6 +201,10 @@ { "id": "decimals", "value": 0 + }, + { + "id": "custom.width", + "value": 73 } ] }, @@ -212,6 +221,10 @@ { "id": "decimals", "value": 1 + }, + { + "id": "custom.width", + "value": 86 } ] }, @@ -358,9 +371,10 @@ ], "show": false }, - "showHeader": true + "showHeader": true, + "sortBy": [] }, - "pluginVersion": "12.0.0", + "pluginVersion": "12.1.0", "targets": [ { "datasource": { @@ -406,13 +420,15 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", "hideFrom": { "legend": false, "tooltip": false, - "vis": false + "vis": false, + "viz": false }, "insertNulls": false, "lineInterpolation": "linear", @@ -436,7 +452,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": 0 }, { "color": "red", @@ -472,7 +489,7 @@ "sort": "desc" } }, - "pluginVersion": "12.0.0", + "pluginVersion": "12.1.0", "targets": [ { "datasource": { @@ -505,13 +522,15 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", "hideFrom": { "legend": false, "tooltip": false, - "vis": false + "vis": false, + "viz": false }, "insertNulls": false, "lineInterpolation": "linear", @@ -535,7 +554,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": 0 }, { "color": "red", @@ -569,7 +589,7 @@ "sort": "none" } }, - "pluginVersion": "12.0.0", + "pluginVersion": "12.1.0", "targets": [ { "datasource": { @@ -602,13 +622,15 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", "hideFrom": { "legend": false, "tooltip": false, - "vis": false + "vis": false, + "viz": false }, "insertNulls": false, "lineInterpolation": "linear", @@ -632,7 +654,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": 0 }, { "color": "red", @@ -668,7 +691,7 @@ "sort": "desc" } }, - "pluginVersion": "12.0.0", + "pluginVersion": "12.1.0", "targets": [ { "datasource": { @@ -701,13 +724,15 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", "hideFrom": { "legend": false, "tooltip": false, - "vis": false + "vis": false, + "viz": false }, "insertNulls": false, "lineInterpolation": "linear", @@ -731,7 +756,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": 0 }, { "color": "red", @@ -765,7 +791,7 @@ "sort": "none" } }, - "pluginVersion": "12.0.0", + "pluginVersion": "12.1.0", "targets": [ { "datasource": { @@ -798,13 +824,15 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", "hideFrom": { "legend": false, "tooltip": false, - "vis": false + "vis": false, + "viz": false }, "insertNulls": false, "lineInterpolation": "linear", @@ -828,7 +856,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": 0 }, { "color": "red", @@ -864,7 +893,7 @@ "sort": "desc" } }, - "pluginVersion": "12.0.0", + "pluginVersion": "12.1.0", "targets": [ { "datasource": { @@ -897,13 +926,15 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", "hideFrom": { "legend": false, "tooltip": false, - "vis": false + "vis": false, + "viz": false }, "insertNulls": false, "lineInterpolation": "linear", @@ -927,7 +958,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": 0 }, { "color": "red", @@ -961,7 +993,7 @@ "sort": "none" } }, - "pluginVersion": "12.0.0", + "pluginVersion": "12.1.0", "targets": [ { "datasource": { @@ -994,13 +1026,15 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", "hideFrom": { "legend": false, "tooltip": false, - "vis": false + "vis": false, + "viz": false }, "insertNulls": false, "lineInterpolation": "linear", @@ -1024,7 +1058,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": 0 }, { "color": "red", @@ -1060,7 +1095,7 @@ "sort": "desc" } }, - "pluginVersion": "12.0.0", + "pluginVersion": "12.1.0", "targets": [ { "datasource": { @@ -1087,33 +1122,17 @@ "x": 0, "y": 46 }, - "id": 11, - "options": { - "content": "## Fast Mode Analysis\n\nThis dashboard uses **fast mode** analysis with simple max-min calculations for optimal performance. It assumes no `pg_stat_statements` reset during the time period.\n\n**Enhanced Features:** Comprehensive query analysis with sortable table view and visual time-series charts for top-performing queries.\n\nFor more detailed analysis with reset handling, use the \"Stat Statements Analysis (Unified)\" dashboard.", - "mode": "markdown" - }, - "pluginVersion": "12.0.0", - "title": "Dashboard Information", - "transparent": true, - "type": "text" - }, - { - "fieldConfig": { - "defaults": {}, - "overrides": [] - }, - "gridPos": { - "h": 4, - "w": 12, - "x": 12, - "y": 46 - }, "id": 12, "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, "content": "## Brought to you by\n\n\n \"Cybertec\n", "mode": "markdown" }, - "pluginVersion": "12.0.0", + "pluginVersion": "12.1.0", "title": "", "transparent": true, "type": "text" @@ -1138,6 +1157,7 @@ }, "definition": "", "includeAll": false, + "label": "Monitored Source", "name": "dbname", "options": [], "query": "SELECT DISTINCT dbname FROM admin.all_distinct_dbname_metrics WHERE metric = 'stat_statements' ORDER BY 1;", @@ -1150,7 +1170,9 @@ "text": "20", "value": "20" }, + "description": "Limit output to top N entries", "includeAll": false, + "label": "Top N", "name": "top", "options": [ { @@ -1189,19 +1211,21 @@ }, { "current": { - "text": "!pgwatch_generated", - "value": "!pgwatch_generated" + "text": ".*", + "value": ".*" }, + "description": "Custom regex filter for queries. Use '!' prefix to exclude, e.g., '!pgwatch_generated' excludes queries containing 'pgwatch_generated'. Use regular expressions like 'SELECT|INSERT' to include only specific patterns.", "includeAll": false, + "label": "Filter RegEx", "name": "query_filter_regex", "options": [ { - "selected": true, + "selected": false, "text": "!pgwatch_generated", "value": "!pgwatch_generated" }, { - "selected": false, + "selected": true, "text": ".*", "value": ".*" }, @@ -1217,8 +1241,7 @@ } ], "query": "!pgwatch_generated,.*,!SELECT,UPDATE|DELETE|INSERT", - "type": "custom", - "description": "Custom regex filter for queries. Use '!' prefix to exclude, e.g., '!pgwatch_generated' excludes queries containing 'pgwatch_generated'. Use regular expressions like 'SELECT|INSERT' to include only specific patterns." + "type": "custom" } ] }, @@ -1230,5 +1253,5 @@ "timezone": "browser", "title": "4. Query Performance Analysis", "uid": "query-performance-analysis", - "version": 1 -} + "version": 4 +} \ No newline at end of file From b55a98557acf08c249fa25cdc243d43a5a865f0b Mon Sep 17 00:00:00 2001 From: Pavlo Golub Date: Fri, 29 Aug 2025 15:41:46 +0200 Subject: [PATCH 4/8] Revert "remove old stat-statements dashboards" This reverts commit 09772815839685bbe6a3d5b4a9ce75f5686207fa. --- .../v12/stat-statements-sql-search.json | 337 ++++ .../v12/stat-statements-top-fast.json | 1405 +++++++++++++++++ .../v12/stat-statements-top-visual.json | 441 ++++++ grafana/postgres/v12/stat-statements-top.json | 1111 +++++++++++++ 4 files changed, 3294 insertions(+) create mode 100644 grafana/postgres/v12/stat-statements-sql-search.json create mode 100644 grafana/postgres/v12/stat-statements-top-fast.json create mode 100644 grafana/postgres/v12/stat-statements-top-visual.json create mode 100644 grafana/postgres/v12/stat-statements-top.json diff --git a/grafana/postgres/v12/stat-statements-sql-search.json b/grafana/postgres/v12/stat-statements-sql-search.json new file mode 100644 index 0000000000..d33f8ebbac --- /dev/null +++ b/grafana/postgres/v12/stat-statements-sql-search.json @@ -0,0 +1,337 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 5, + "links": [], + "panels": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/time/" + }, + "properties": [ + { + "id": "unit", + "value": "ms" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "calls" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/queryid/" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Go to Query Details dash", + "url": "/d/single-query-details?var-dbname=$dbname&var-queryid=$__cell" + } + ] + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/last_exec/" + }, + "properties": [ + { + "id": "unit", + "value": "dtdurations" + }, + { + "id": "custom.align" + } + ] + } + ] + }, + "gridPos": { + "h": 16, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 2, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n total_time, mean_time, calls as total_calls, seconds_since_last_exec, queryid, query\nFROM (\n\nSELECT\n DISTINCT ON (queryid) queryid, time, total_time, mean_time, calls, query\nFROM (\n\nSELECT\n time, (data->>'total_time')::float as total_time, (data->>'total_time')::float / (data->>'calls')::int8 as mean_time, (data->>'calls')::int8 as calls, tag_data->>'queryid' as queryid, tag_data->>'query' as query\nFROM stat_statements\nWHERE\n dbname = '$dbname'\n AND time > now() - '$calls_interval'::interval\n AND tag_data->>'query' ~* '$sql_fragment'\n AND CASE WHEN length('$sql_fragment') > 2 THEN true ELSE false END\n) x\nORDER BY queryid, time DESC, mean_time, calls, query\n\n) y\nJOIN LATERAL \n (select (extract(epoch from now() - prev.time))::int8 as seconds_since_last_exec\n from stat_statements prev\n where dbname = '$dbname' and time > now() - '$calls_interval'::interval\n and prev.time < y.time and (prev.data->>'calls')::int8 != y.calls\n order by time desc limit 1\n) z on true\n\nORDER BY total_time DESC LIMIT 100", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Matching Queries", + "transformations": [ + { + "id": "merge", + "options": { + "reducers": [] + } + } + ], + "type": "table" + }, + { + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 16 + }, + "id": 4, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "### Brought to you by\n\n[![Cybertec – The PostgreSQL Database Company](https://www.cybertec-postgresql.com/wp-content/uploads/2025/02/cybertec-logo-white-blue.svg)](https://www.cybertec-postgresql.com/en/)\n", + "mode": "markdown" + }, + "pluginVersion": "12.0.0", + "title": "", + "transparent": true, + "type": "text" + } + ], + "preload": false, + "refresh": "", + "schemaVersion": 41, + "tags": [ + "pgwatch" + ], + "templating": { + "list": [ + { + "current": { + "text": "demo", + "value": "demo" + }, + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "definition": "SELECT DISTINCT dbname FROM admin.all_distinct_dbname_metrics WHERE metric = 'stat_statements' ORDER BY 1;", + "includeAll": false, + "name": "dbname", + "options": [], + "query": "SELECT DISTINCT dbname FROM admin.all_distinct_dbname_metrics WHERE metric = 'stat_statements' ORDER BY 1;", + "refresh": 1, + "regex": "", + "type": "query" + }, + { + "current": { + "text": "", + "value": "" + }, + "label": "SQL search fragment (case insensitive, 3 char min.)", + "name": "sql_fragment", + "options": [ + { + "selected": true, + "text": "", + "value": "" + } + ], + "query": "", + "type": "textbox" + }, + { + "auto": false, + "auto_count": 30, + "auto_min": "10s", + "current": { + "text": "12h", + "value": "12h" + }, + "label": "Having some executions within last", + "name": "calls_interval", + "options": [ + { + "selected": false, + "text": "30m", + "value": "30m" + }, + { + "selected": false, + "text": "1h", + "value": "1h" + }, + { + "selected": false, + "text": "6h", + "value": "6h" + }, + { + "selected": true, + "text": "12h", + "value": "12h" + }, + { + "selected": false, + "text": "1d", + "value": "1d" + }, + { + "selected": false, + "text": "7d", + "value": "7d" + }, + { + "selected": false, + "text": "14d", + "value": "14d" + }, + { + "selected": false, + "text": "30d", + "value": "30d" + } + ], + "query": "30m,1h,6h,12h,1d,7d,14d,30d", + "refresh": 2, + "type": "interval" + } + ] + }, + "time": { + "from": "now-12h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Stat Statements SQL Search", + "uid": "stat-statements-sql-search", + "version": 1 +} \ No newline at end of file diff --git a/grafana/postgres/v12/stat-statements-top-fast.json b/grafana/postgres/v12/stat-statements-top-fast.json new file mode 100644 index 0000000000..efa5c9905a --- /dev/null +++ b/grafana/postgres/v12/stat-statements-top-fast.json @@ -0,0 +1,1405 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "Assumes no pg_stat_statements reset appeared in the selected time frame", + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 9, + "links": [], + "panels": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "description": "", + "fieldConfig": { + "defaults": { + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Time" + }, + "properties": [ + { + "id": "displayName", + "value": "Time" + }, + { + "id": "custom.hidden", + "value": true + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "queryid" + }, + "properties": [ + { + "id": "displayName", + "value": "Query ID" + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Opens 'Single query details' dashboard for that queryid", + "url": "/d/single-query-details?orgId=1&var-dbname=$dbname&var-queryid=$__cell&from=$__from&to=$__to" + } + ] + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "top" + }, + "properties": [ + { + "id": "displayName", + "value": "Total runtime" + }, + { + "id": "unit", + "value": "ms" + }, + { + "id": "decimals", + "value": 1 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "query" + }, + "properties": [ + { + "id": "displayName", + "value": "Query" + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "approx_pct_db_total_time" + }, + "properties": [ + { + "id": "unit", + "value": "percent" + }, + { + "id": "decimals", + "value": 1 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Avg. runtime" + }, + "properties": [ + { + "id": "unit", + "value": "ms" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Calls" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "custom.align" + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 16, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "alias": "ass", + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "format": "table", + "group": [], + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "metricColumn": "none", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT top(\"spread\", \"queryid\", \"query\", $top) FROM (SELECT spread(\"total_time\") FROM \"stat_statements\" WHERE $timeFilter AND \"dbname\" = '$dbname' GROUP BY time(3650d), \"queryid\", \"query\" fill(none) ) WHERE spread > 0", + "rawQuery": true, + "rawSql": "select\n tt as top,\n tt / calls as \"Avg. runtime\",\n calls as \"Calls\",\n 100 * tt / (select sum(tt_agg) from (select tag_data->>'queryid', max((data->>'total_time')::float) - min((data->>'total_time')::float) as tt_agg from stat_statements where dbname = '$dbname' and $__timeFilter(time) group by 1 having count(*) > 1) x) as approx_pct_db_total_time,\n queryid,\n (select data->>'users' from stat_statements where $__timeFilter(time) and dbname = '$dbname' and tag_data->>'queryid' = queryid order by time desc limit 1) as \"Users\", \n case when length(query) > 250 then query::varchar(250) || '...' else query end as query\nfrom (\n\n select\n tag_data->>'queryid' as queryid, tag_data->>'query' as query,\n max((data->>'total_time')::numeric) - min((data->>'total_time')::numeric) as tt,\n max((data->>'calls')::int8) - min((data->>'calls')::int8) as calls,\n min(time) as min_time,\n max(time) as max_time\n from stat_statements\n where dbname = '$dbname'\n and $__timeFilter(time)\n and case when '$hide_pgwatch_generated' = 'yes' then not tag_data->>'query' ~* E'\\\\(extract\\\\(\\\\$\\\\d+\\\\W*from\\\\W*now\\\\(\\\\)\\\\)\\\\W?\\\\*\\\\W*\\\\$\\\\d+\\\\).*::\\\\w+\\\\W+as\\\\W+epoch_ns\\\\W*,'\n and not tag_data->>'query' ~* E'/\\\\*\\\\W*pgwatch_generated\\\\W*\\\\*/' else true end\n group by\n 1, 2\n\n) x\nwhere calls > 0 and tt > 0\norder by 1 desc nulls last\nlimit $top\n\n", + "refId": "A", + "resultFormat": "table", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Top queries by total runtime", + "type": "table" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "description": "", + "fieldConfig": { + "defaults": { + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Time" + }, + "properties": [ + { + "id": "displayName", + "value": "Time" + }, + { + "id": "custom.hidden", + "value": true + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "queryid" + }, + "properties": [ + { + "id": "displayName", + "value": "Query ID" + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Opens 'Single query details' dashboard for that queryid", + "url": "/d/single-query-details?orgId=1&var-dbname=$dbname&var-queryid=$__cell&from=$__from&to=$__to" + } + ] + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "top" + }, + "properties": [ + { + "id": "displayName", + "value": "Avg. runtime" + }, + { + "id": "unit", + "value": "ms" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "query" + }, + "properties": [ + { + "id": "displayName", + "value": "Query" + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total time" + }, + "properties": [ + { + "id": "unit", + "value": "ms" + }, + { + "id": "decimals", + "value": 1 + }, + { + "id": "custom.align" + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 7 + }, + "id": 15, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "alias": "ass", + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "format": "table", + "group": [], + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "metricColumn": "none", + "orderByTime": "ASC", + "policy": "default", + "query": "select top(avg, \"queryid\", \"query\", $top) AS top from (select mean(t) / mean(c) AS avg from (SELECT spread(\"total_time\") AS t, spread(\"calls\") AS c FROM \"stat_statements\" WHERE $timeFilter AND dbname = '$dbname' GROUP BY time(3650d), \"queryid\", \"query\" fill(none) ) where $timeFilter AND c > 0 group by time(3650d), \"queryid\", \"query\" )", + "rawQuery": true, + "rawSql": "select\n tt / calls as top,\n tt as \"Total time\",\n calls as \"Calls\",\n queryid,\n (select data->>'users' from stat_statements where $__timeFilter(time) and dbname = '$dbname' and tag_data->>'queryid' = queryid order by time desc limit 1) as \"Users\",\n case when length(query) > 200 then query::varchar(200) || '...' else query end as query\nfrom (\n select\n tag_data->>'queryid' as queryid, tag_data->>'query' as query,\n max((data->>'total_time')::numeric) - min((data->>'total_time')::numeric) as tt,\n max((data->>'calls')::int8) - min((data->>'calls')::int8) as calls\n from stat_statements\n where dbname = '$dbname'\n and $__timeFilter(time)\n and case when '$hide_pgwatch_generated' = 'yes' then not tag_data->>'query' ~* E'\\\\(extract\\\\(\\\\$\\\\d+\\\\W*from\\\\W*now\\\\(\\\\)\\\\)\\\\W?\\\\*\\\\W*\\\\$\\\\d+\\\\).*::\\\\w+\\\\W+as\\\\W+epoch_ns\\\\W*,'\n and not tag_data->>'query' ~* E'/\\\\*\\\\W*pgwatch_generated\\\\W*\\\\*/' else true end\n group by\n 1, 2\n) x\nwhere calls > 0 and tt > 0\norder by 1 desc nulls last\nlimit $top\n\n", + "refId": "A", + "resultFormat": "table", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Top queries by avg. runtime", + "type": "table" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "description": "", + "fieldConfig": { + "defaults": { + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Time" + }, + "properties": [ + { + "id": "displayName", + "value": "Time" + }, + { + "id": "custom.hidden", + "value": true + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "queryid" + }, + "properties": [ + { + "id": "displayName", + "value": "Query ID" + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Opens 'Single query details' dashboard for that queryid", + "url": "/d/single-query-details?orgId=1&var-dbname=$dbname&var-queryid=$__cell&from=$__from&to=$__to" + } + ] + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "top" + }, + "properties": [ + { + "id": "displayName", + "value": "Calls " + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 1 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "query" + }, + "properties": [ + { + "id": "displayName", + "value": "Query" + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total time" + }, + "properties": [ + { + "id": "unit", + "value": "ms" + }, + { + "id": "decimals", + "value": 1 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Avg. runtime" + }, + "properties": [ + { + "id": "unit", + "value": "ms" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 14 + }, + "id": 14, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "alias": "ass", + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "format": "table", + "group": [], + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "metricColumn": "none", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT top(\"spread\", \"queryid\", \"query\", $top) FROM (SELECT spread(\"calls\") FROM \"stat_statements\" WHERE $timeFilter AND \"dbname\" = '$dbname' GROUP BY time(3650d), \"queryid\", \"query\" fill(none) ) WHERE spread > 0", + "rawQuery": true, + "rawSql": "select\n calls as top,\n total_time as \"Total time\",\n total_time / calls as \"Avg. runtime\",\n queryid,\n (select data->>'users' from stat_statements where $__timeFilter(time) and dbname = '$dbname' and tag_data->>'queryid' = queryid order by time desc limit 1) as \"Users\", \n case when length(query) > 200 then query::varchar(200) || '...' else query end as query\nfrom (\n select\n tag_data->>'queryid' as queryid, tag_data->>'query' as query,\n max((data->>'calls')::int8) - min((data->>'calls')::int8) as calls,\n max((data->>'total_time')::numeric) - min((data->>'total_time')::numeric) as total_time\n from stat_statements\n where dbname = '$dbname'\n and $__timeFilter(time)\n and case when '$hide_pgwatch_generated' = 'yes' then not tag_data->>'query' ~* E'\\\\(extract\\\\(\\\\$\\\\d+\\\\W*from\\\\W*now\\\\(\\\\)\\\\)\\\\W?\\\\*\\\\W*\\\\$\\\\d+\\\\).*::\\\\w+\\\\W+as\\\\W+epoch_ns\\\\W*,'\n and not tag_data->>'query' ~* E'/\\\\*\\\\W*pgwatch_generated\\\\W*\\\\*/' else true end \n group by\n 1, 2\n) x\nwhere calls > 0\norder by 1 desc nulls last\nlimit $top\n\n", + "refId": "A", + "resultFormat": "table", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Top queries by calls", + "type": "table" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "description": "total_time - blk_read_time -blk_write_time. Requires track_io_timing=on", + "fieldConfig": { + "defaults": { + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Time" + }, + "properties": [ + { + "id": "displayName", + "value": "Time" + }, + { + "id": "custom.hidden", + "value": true + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "top" + }, + "properties": [ + { + "id": "displayName", + "value": "CPU time" + }, + { + "id": "unit", + "value": "ms" + }, + { + "id": "decimals", + "value": 1 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "queryid" + }, + "properties": [ + { + "id": "displayName", + "value": "Query ID" + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "links", + "value": [ + { + "targetBlank": false, + "title": "Opens 'Single query details' dashboard for that queryid", + "url": "/d/single-query-details?orgId=1&var-dbname=$dbname&var-queryid=$__cell&from=$__from&to=$__to" + } + ] + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "query" + }, + "properties": [ + { + "id": "displayName", + "value": "Query" + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Avg. runtime" + }, + "properties": [ + { + "id": "unit", + "value": "ms" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 21 + }, + "id": 13, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "format": "table", + "group": [], + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "metricColumn": "none", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT top(\"spread\", \"queryid\", \"query\", $top) FROM (SELECT spread(\"blk_read_time\") + spread(\"blk_write_time\") AS spread FROM \"stat_statements\" WHERE $timeFilter AND \"dbname\" = '$dbname' GROUP BY time(3650d), \"queryid\", \"query\" fill(none) ) WHERE spread > 0", + "rawQuery": true, + "rawSql": "select\n (tt - wt - rt)::int8 as top,\n calls as \"Calls\",\n tt / calls as \"Avg. runtime\",\n queryid,\n (select data->>'users' from stat_statements where $__timeFilter(time) and dbname = '$dbname' and tag_data->>'queryid' = queryid order by time desc limit 1) as \"Users\", \n case when length(query) > 200 then query::varchar(200) || '...' else query end as query\nfrom (\n select\n tag_data->>'queryid' as queryid, tag_data->>'query' as query,\n max((data->>'total_time')::float8) - min((data->>'total_time')::float8) as tt,\n max((data->>'blk_read_time')::float8) - min((data->>'blk_read_time')::float8) as rt,\n max((data->>'blk_write_time')::float8) - min((data->>'blk_write_time')::float8) as wt,\n max((data->>'calls')::int8) - min((data->>'calls')::int8) as calls\n from stat_statements\n where dbname = '$dbname'\n and $__timeFilter(time)\n and case when '$hide_pgwatch_generated' = 'yes' then not tag_data->>'query' ~* E'\\\\(extract\\\\(\\\\$\\\\d+\\\\W*from\\\\W*now\\\\(\\\\)\\\\)\\\\W?\\\\*\\\\W*\\\\$\\\\d+\\\\).*::\\\\w+\\\\W+as\\\\W+epoch_ns\\\\W*,'\n and not tag_data->>'query' ~* E'/\\\\*\\\\W*pgwatch_generated\\\\W*\\\\*/' else true end \n group by\n 1, 2\n) x\nwhere tt - wt - rt > 0 and calls > 0\norder by 1 desc nulls last\nlimit $top\n\n", + "refId": "A", + "resultFormat": "table", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Top queries by CPU time", + "type": "table" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "description": "Does not include Shared Buffer activities. Same as 'By total runtime' if no direct IO was performed. Requires track_io_timing=on", + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 28 + }, + "id": 12, + "options": {}, + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "format": "table", + "group": [], + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "metricColumn": "none", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT top(\"spread\", \"queryid\", \"query\", $top) FROM (SELECT spread(\"blk_read_time\") + spread(\"blk_write_time\") AS spread FROM \"stat_statements\" WHERE $timeFilter AND \"dbname\" = '$dbname' GROUP BY time(3650d), \"queryid\", \"query\" fill(none) ) WHERE spread > 0", + "rawQuery": true, + "rawSql": "select\n wt + rt as top,\n tt as \"Total time\",\n queryid,\n (select data->>'users' from stat_statements where $__timeFilter(time) and dbname = '$dbname' and tag_data->>'queryid' = queryid order by time desc limit 1) as \"Users\", \n case when length(query) > 200 then query::varchar(200) || '...' else query end as query\nfrom (\n select\n tag_data->>'queryid' as queryid, max(tag_data->>'query') as query,\n max((data->>'blk_read_time')::float8) - min((data->>'blk_read_time')::float8) as rt,\n max((data->>'blk_write_time')::float8) - min((data->>'blk_write_time')::float8) as wt,\n max((data->>'total_time')::float8) - min((data->>'total_time')::float8) as tt\n from stat_statements\n where dbname = '$dbname'\n and $__timeFilter(time)\n and case when '$hide_pgwatch_generated' = 'yes' then not tag_data->>'query' ~* E'\\\\(extract\\\\(\\\\$\\\\d+\\\\W*from\\\\W*now\\\\(\\\\)\\\\)\\\\W?\\\\*\\\\W*\\\\$\\\\d+\\\\).*::\\\\w+\\\\W+as\\\\W+epoch_ns\\\\W*,'\n and not tag_data->>'query' ~* E'/\\\\*\\\\W*pgwatch_generated\\\\W*\\\\*/' else true end \n group by\n 1\n) x\nwhere rt + wt > 0.1\norder by 1 desc nulls last\nlimit $top\n\n", + "refId": "A", + "resultFormat": "table", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Top queries by direct (backend) IO", + "type": "table" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "description": "Shared buffer + temp buffer reading / writing", + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 35 + }, + "id": 11, + "options": {}, + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "format": "table", + "group": [], + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "metricColumn": "none", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT top(\"spread\", \"queryid\", \"query\", $top) FROM (SELECT spread(\"blk_read_time\") + spread(\"blk_write_time\") AS spread FROM \"stat_statements\" WHERE $timeFilter AND \"dbname\" = '$dbname' GROUP BY time(3650d), \"queryid\", \"query\" fill(none) ) WHERE spread > 0", + "rawQuery": true, + "rawSql": "select\n (shared_blks_hit + shared_blks_read + shared_blks_dirtied + shared_blks_written)*8192 /*assuming default 8k block size*/ as top,\n (shared_blks_hit + shared_blks_read + shared_blks_dirtied + shared_blks_written)*8192 / calls as \"Per call\",\n calls as \"Calls\",\n total_time / calls as \"Avg. runtime\",\n queryid,\n (select data->>'users' from stat_statements where $__timeFilter(time) and dbname = '$dbname' and tag_data->>'queryid' = queryid order by time desc limit 1) as \"Users\", \n case when length(query) > 200 then query::varchar(200) || '...' else query end as query\nfrom (\n select\n tag_data->>'queryid' as queryid,\n tag_data->>'query' as query,\n max((data->>'shared_blks_hit')::int8) - min((data->>'shared_blks_hit')::int8) as shared_blks_hit,\n max((data->>'shared_blks_read')::int8) - min((data->>'shared_blks_read')::int8) as shared_blks_read,\n max((data->>'shared_blks_dirtied')::int8) - min((data->>'shared_blks_dirtied')::int8) as shared_blks_dirtied,\n max((data->>'shared_blks_written')::int8) - min((data->>'shared_blks_written')::int8) as shared_blks_written,\n max((data->>'calls')::int8) - min((data->>'calls')::int8) as calls,\n max((data->>'total_time')::float) - min((data->>'total_time')::float) as total_time\n from stat_statements\n where dbname = '$dbname'\n and $__timeFilter(time)\n and case when '$hide_pgwatch_generated' = 'yes' then not tag_data->>'query' ~* E'\\\\(extract\\\\(\\\\$\\\\d+\\\\W*from\\\\W*now\\\\(\\\\)\\\\)\\\\W?\\\\*\\\\W*\\\\$\\\\d+\\\\).*::\\\\w+\\\\W+as\\\\W+epoch_ns\\\\W*,'\n and not tag_data->>'query' ~* E'/\\\\*\\\\W*pgwatch_generated\\\\W*\\\\*/' else true end\n group by\n 1, 2\n) x\nwhere calls > 0\norder by 1 desc nulls last\nlimit $top", + "refId": "A", + "resultFormat": "table", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Top by block bandwith (assuming 8K blocks)", + "type": "table" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "description": "Based on pg_stat_statements.temp_blks_written", + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 42 + }, + "id": 17, + "options": {}, + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "format": "table", + "group": [], + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "metricColumn": "none", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT top(\"spread\", \"queryid\", \"query\", $top) FROM (SELECT spread(\"blk_read_time\") + spread(\"blk_write_time\") AS spread FROM \"stat_statements\" WHERE $timeFilter AND \"dbname\" = '$dbname' GROUP BY time(3650d), \"queryid\", \"query\" fill(none) ) WHERE spread > 0", + "rawQuery": true, + "rawSql": "select\n temp_blks_written * 8192 /*assuming default 8k block size*/ as top,\n (temp_blks_read * 8192) / calls as \"Temp blocks read\",\n total_time as \"Total runtime\",\n calls as \"Calls\",\n total_time / calls as \"Avg. runtime\",\n queryid,\n (select data->>'users' from stat_statements where $__timeFilter(time) and dbname = '$dbname' and tag_data->>'queryid' = queryid order by time desc limit 1) as \"Users\", \n case when length(query) > 200 then query::varchar(200) || '...' else query end as query\nfrom (\n select\n tag_data->>'queryid' as queryid,\n tag_data->>'query' as query,\n max((data->>'temp_blks_read')::int8) - min((data->>'temp_blks_read')::int8) as temp_blks_read,\n max((data->>'temp_blks_written')::int8) - min((data->>'temp_blks_written')::int8) as temp_blks_written,\n max((data->>'calls')::int8) - min((data->>'calls')::int8) as calls,\n max((data->>'total_time')::float) - min((data->>'total_time')::float) as total_time\n from stat_statements\n where dbname = '$dbname'\n and $__timeFilter(time)\n and case when '$hide_pgwatch_generated' = 'yes' then not tag_data->>'query' ~* E'\\\\(extract\\\\(\\\\$\\\\d+\\\\W*from\\\\W*now\\\\(\\\\)\\\\)\\\\W?\\\\*\\\\W*\\\\$\\\\d+\\\\).*::\\\\w+\\\\W+as\\\\W+epoch_ns\\\\W*,'\n and not tag_data->>'query' ~* E'/\\\\*\\\\W*pgwatch_generated\\\\W*\\\\*/' else true end\n group by\n 1, 2\n) x\nwhere temp_blks_written > 0\norder by 1 desc nulls last\nlimit $top", + "refId": "A", + "resultFormat": "table", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Top by temp blocks (assuming 8K blocks)", + "type": "table" + }, + { + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 12, + "x": 0, + "y": 49 + }, + "id": 4, + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 12, + "x": 12, + "y": 49 + }, + "id": 18, + "maxDataPoints": 100, + "options": {}, + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select\n0 as time,\ncoalesce ((\n\nselect 1 from (\nselect\n (data->>'xact_commit')::int8 as xact_commit,\n lag((data->>'xact_commit')::int8) over (order by time) as xact_commit_lag\nfrom\n db_stats\nwhere\n $__timeFilter(time)\n and dbname = '$dbname'\n) x\nwhere xact_commit_lag > xact_commit\nlimit 1\n\n), 0) as was_reset", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "", + "transparent": true, + "type": "stat" + } + ], + "preload": false, + "refresh": "", + "schemaVersion": 41, + "tags": [ + "pgwatch" + ], + "templating": { + "list": [ + { + "current": { + "text": "demo", + "value": "demo" + }, + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "definition": "", + "includeAll": false, + "name": "dbname", + "options": [], + "query": "SELECT DISTINCT dbname FROM admin.all_distinct_dbname_metrics WHERE metric = 'stat_statements' ORDER BY 1;", + "refresh": 1, + "regex": "", + "type": "query" + }, + { + "current": { + "text": "5", + "value": "5" + }, + "includeAll": false, + "name": "top", + "options": [ + { + "selected": false, + "text": "1", + "value": "1" + }, + { + "selected": false, + "text": "3", + "value": "3" + }, + { + "selected": true, + "text": "5", + "value": "5" + }, + { + "selected": false, + "text": "10", + "value": "10" + }, + { + "selected": false, + "text": "15", + "value": "15" + }, + { + "selected": false, + "text": "20", + "value": "20" + }, + { + "selected": false, + "text": "30", + "value": "30" + }, + { + "selected": false, + "text": "40", + "value": "40" + }, + { + "selected": false, + "text": "50", + "value": "50" + } + ], + "query": "1,3,5,10,15,20,30,40,50", + "type": "custom" + }, + { + "current": { + "text": "yes", + "value": "yes" + }, + "includeAll": false, + "name": "hide_pgwatch_generated", + "options": [ + { + "selected": true, + "text": "yes", + "value": "yes" + }, + { + "selected": false, + "text": "no", + "value": "no" + } + ], + "query": "yes,no", + "type": "custom" + } + ] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "Stat statements Top (Fast)", + "uid": "stat-statements-top-fast", + "version": 1 +} \ No newline at end of file diff --git a/grafana/postgres/v12/stat-statements-top-visual.json b/grafana/postgres/v12/stat-statements-top-visual.json new file mode 100644 index 0000000000..4ca51072ae --- /dev/null +++ b/grafana/postgres/v12/stat-statements-top-visual.json @@ -0,0 +1,441 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 4, + "links": [], + "panels": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "description": "Assumes that pg_stat_statement data has not been reset in the selected time frame. Click on the graph data links for the 'Query details' view.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 12, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 2, + "options": { + "dataLinks": [ + { + "targetBlank": true, + "title": "Query details", + "url": "/d/single-query-details?$__all_variables&var-queryid=${__series.name}&${__url_time_range}" + } + ], + "legend": { + "calcs": [ + "mean", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n $__timeGroup(time, $agg_interval),\n max((data->>'calls')::int8) - min((data->>'calls')::int8) as calls,\n tag_data->>'queryid' as queryid\nFROM\n stat_statements\nWHERE\n $__timeFilter(time)\n AND dbname = '$dbname'\n AND tag_data->>'queryid' IN (\n select tag_data->>'queryid'\n from stat_statements\n where $__timeFilter(time) and dbname = '$dbname'\n group by tag_data->>'queryid'\n having max((data->>'calls')::int8) - min((data->>'calls')::int8) > 0\n order by max((data->>'calls')::int8) - min((data->>'calls')::int8) desc\n limit $top\n )\nGROUP BY 1, 3\nORDER by 1\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Top $top queries by calls", + "type": "timeseries" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "description": "Assumes that pg_stat_statement data has not been reset in the selected time frame. Click on the graph data links for the 'Query details' view.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 12, + "w": 24, + "x": 0, + "y": 12 + }, + "id": 3, + "options": { + "dataLinks": [ + { + "targetBlank": true, + "title": "Query details", + "url": "/d/single-query-details?$__all_variables&var-queryid=${__series.name}&${__url_time_range}" + } + ], + "legend": { + "calcs": [ + "mean", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n $__timeGroup(time, $agg_interval),\n max((data->>'total_time')::float) - min((data->>'total_time')::float) as total_time,\n tag_data->>'queryid' as queryid\nFROM\n stat_statements\nWHERE\n $__timeFilter(time)\n AND dbname = '$dbname'\n AND tag_data->>'queryid' IN (\n select tag_data->>'queryid'\n from stat_statements\n where $__timeFilter(time) and dbname = '$dbname'\n group by tag_data->>'queryid'\n having max((data->>'total_time')::float) - min((data->>'total_time')::float) > 0\n order by max((data->>'total_time')::float) - min((data->>'total_time')::float) desc\n limit $top\n )\nGROUP BY 1, 3\nORDER by 1\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Top $top queries by total time", + "type": "timeseries" + }, + { + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 24 + }, + "id": 5, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "### Brought to you by\n\n[![Cybertec – The PostgreSQL Database Company](https://www.cybertec-postgresql.com/wp-content/uploads/2025/02/cybertec-logo-white-blue.svg)](https://www.cybertec-postgresql.com/en/)\n", + "mode": "markdown" + }, + "pluginVersion": "12.0.0", + "title": "", + "transparent": true, + "type": "text" + } + ], + "preload": false, + "refresh": "", + "schemaVersion": 41, + "tags": [ + "pgwatch" + ], + "templating": { + "list": [ + { + "current": { + "text": "demo", + "value": "demo" + }, + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "definition": "SELECT DISTINCT dbname FROM admin.all_distinct_dbname_metrics WHERE metric = 'stat_statements' ORDER BY 1;", + "includeAll": false, + "name": "dbname", + "options": [], + "query": "SELECT DISTINCT dbname FROM admin.all_distinct_dbname_metrics WHERE metric = 'stat_statements' ORDER BY 1;", + "refresh": 1, + "regex": "", + "type": "query" + }, + { + "auto": false, + "auto_count": 30, + "auto_min": "10s", + "current": { + "text": "15m", + "value": "15m" + }, + "name": "agg_interval", + "options": [ + { + "selected": false, + "text": "5m", + "value": "5m" + }, + { + "selected": false, + "text": "10m", + "value": "10m" + }, + { + "selected": true, + "text": "15m", + "value": "15m" + }, + { + "selected": false, + "text": "30m", + "value": "30m" + }, + { + "selected": false, + "text": "1h", + "value": "1h" + }, + { + "selected": false, + "text": "6h", + "value": "6h" + }, + { + "selected": false, + "text": "12h", + "value": "12h" + }, + { + "selected": false, + "text": "1d", + "value": "1d" + } + ], + "query": "5m,10m,15m,30m,1h,6h,12h,1d", + "refresh": 2, + "type": "interval" + }, + { + "current": { + "text": "5", + "value": "5" + }, + "includeAll": false, + "name": "top", + "options": [ + { + "selected": false, + "text": "1", + "value": "1" + }, + { + "selected": false, + "text": "3", + "value": "3" + }, + { + "selected": true, + "text": "5", + "value": "5" + }, + { + "selected": false, + "text": "7", + "value": "7" + }, + { + "selected": false, + "text": "10", + "value": "10" + }, + { + "selected": false, + "text": "15", + "value": "15" + } + ], + "query": "1,3,5,7,10,15", + "type": "custom" + } + ] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Stat Statements Top (Visual)", + "uid": "stat-statements-top-visual", + "version": 6 +} \ No newline at end of file diff --git a/grafana/postgres/v12/stat-statements-top.json b/grafana/postgres/v12/stat-statements-top.json new file mode 100644 index 0000000000..edb98e9d0e --- /dev/null +++ b/grafana/postgres/v12/stat-statements-top.json @@ -0,0 +1,1111 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 29, + "links": [], + "panels": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "description": "", + "fieldConfig": { + "defaults": { + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Time" + }, + "properties": [ + { + "id": "displayName", + "value": "Time" + }, + { + "id": "custom.hidden", + "value": true + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "queryid" + }, + "properties": [ + { + "id": "displayName", + "value": "Query ID" + }, + { + "id": "unit", + "value": "none" + }, + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Opens 'Single query details' dashboard for that queryid", + "url": "/d/single-query-details?orgId=1&var-dbname=$dbname&var-queryid=$__cell&from=$__from&to=$__to" + } + ] + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "top" + }, + "properties": [ + { + "id": "displayName", + "value": "Total runtime" + }, + { + "id": "unit", + "value": "ms" + }, + { + "id": "decimals", + "value": 1 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "query" + }, + "properties": [ + { + "id": "displayName", + "value": "Query" + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "approx_pct_db_total_time" + }, + "properties": [ + { + "id": "unit", + "value": "percent" + }, + { + "id": "decimals", + "value": 1 + }, + { + "id": "custom.align" + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 5, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "alias": "ass", + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "format": "table", + "group": [], + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "metricColumn": "none", + "orderByTime": "ASC", + "policy": "default", + "rawQuery": true, + "rawSql": "select\n top,\n approx_pct_db_total_time,\n queryid,\n (select data->>'users' from stat_statements where $__timeFilter(time) and dbname = '$dbname' and tag_data->>'queryid' = queryid order by time desc limit 1) as \"Users\",\n query\nfrom (\nselect\n (sum(tt - tt_lag))::int8 as top,\n round(((sum(tt - tt_lag))::int8 / total::numeric)*100, 1) as approx_pct_db_total_time,\n queryid,\n case when length(query) > 250 then query::varchar(250) || '...' else query end as query\nfrom (\nselect\n *,\n sum(tt - tt_lag) over() as total\nfrom (\n select\n tag_data->>'queryid' as queryid, tag_data->>'query' as query, data->>'users' as users,\n (data->>'total_time')::float8 as tt, lag((data->>'total_time')::float8) over w as tt_lag,\n time\n from stat_statements\n where dbname = '$dbname'\n and $__timeFilter(time)\n and case when '$hide_pgwatch_generated' = 'yes' then not tag_data->>'query' ~* E'\\\\(extract\\\\(\\\\$\\\\d+\\\\W*from\\\\W*now\\\\(\\\\)\\\\)\\\\W?\\\\*\\\\W*\\\\$\\\\d+\\\\).*::\\\\w+\\\\W+as\\\\W+epoch_ns\\\\W*,'\n and not tag_data->>'query' ~* E'/\\\\*\\\\W*pgwatch_generated\\\\W*\\\\*/' else true end\n window w as (partition by tag_data->>'queryid' order by time)\n) x\nwhere tt >= tt_lag\n) y\ngroup by total,queryid,query\nhaving sum(tt - tt_lag) > 0\norder by 1 desc nulls last\nlimit $top\n) z\norder by 1 desc nulls last", + "refId": "A", + "resultFormat": "table", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Top queries by total runtime", + "type": "table" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "description": "", + "fieldConfig": { + "defaults": { + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Time" + }, + "properties": [ + { + "id": "displayName", + "value": "Time" + }, + { + "id": "custom.hidden", + "value": true + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "queryid" + }, + "properties": [ + { + "id": "displayName", + "value": "Query ID" + }, + { + "id": "unit", + "value": "none" + }, + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Opens 'Single query details' dashboard for that queryid", + "url": "/d/single-query-details?orgId=1&var-dbname=$dbname&var-queryid=$__cell&from=$__from&to=$__to" + } + ] + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "top" + }, + "properties": [ + { + "id": "displayName", + "value": "Avg. runtime" + }, + { + "id": "unit", + "value": "ms" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "query" + }, + "properties": [ + { + "id": "displayName", + "value": "Query" + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 7 + }, + "id": 6, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "alias": "ass", + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "format": "table", + "group": [], + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "metricColumn": "none", + "orderByTime": "ASC", + "policy": "default", + "rawQuery": true, + "rawSql": "select\n top,\n queryid,\n (select data->>'users' from stat_statements where $__timeFilter(time) and dbname = '$dbname' and tag_data->>'queryid' = queryid order by time desc limit 1) as \"Users\",\n query\nfrom (\nselect\n (avg((tt - tt_lag)::numeric / (calls - calls_lag)))::int8 as top,\n queryid,\n case when length(query) > 200 then query::varchar(200) || '...' else query end as query\nfrom (\n select\n tag_data->>'queryid' as queryid, tag_data->>'query' as query, data->>'users' as users,\n (data->>'total_time')::float8 as tt, lag((data->>'total_time')::float8) over w as tt_lag,\n (data->>'calls')::int8 as calls, lag((data->>'calls')::int8) over w as calls_lag,\n time\n from stat_statements\n where dbname = '$dbname'\n and $__timeFilter(time)\n and case when '$hide_pgwatch_generated' = 'yes' then not tag_data->>'query' ~* E'\\\\(extract\\\\(\\\\$\\\\d+\\\\W*from\\\\W*now\\\\(\\\\)\\\\)\\\\W?\\\\*\\\\W*\\\\$\\\\d+\\\\).*::\\\\w+\\\\W+as\\\\W+epoch_ns\\\\W*,'\n and not tag_data->>'query' ~* E'/\\\\*\\\\W*pgwatch_generated\\\\W*\\\\*/' else true end\n window w as (partition by tag_data->>'queryid' order by time)\n) x\nwhere calls > calls_lag\ngroup by 2, 3\norder by 1 desc nulls last\nlimit $top\n) z\norder by 1 desc nulls last", + "refId": "A", + "resultFormat": "table", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Top queries by avg. runtime", + "type": "table" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "description": "", + "fieldConfig": { + "defaults": { + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Time" + }, + "properties": [ + { + "id": "displayName", + "value": "Time" + }, + { + "id": "custom.hidden", + "value": true + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "queryid" + }, + "properties": [ + { + "id": "displayName", + "value": "Query ID" + }, + { + "id": "unit", + "value": "none" + }, + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Opens 'Single query details' dashboard for that queryid", + "url": "/d/single-query-details?orgId=1&var-dbname=$dbname&var-queryid=$__cell&from=$__from&to=$__to" + } + ] + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "top" + }, + "properties": [ + { + "id": "displayName", + "value": "Calls " + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 1 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "query" + }, + "properties": [ + { + "id": "displayName", + "value": "Query" + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 14 + }, + "id": 7, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "alias": "ass", + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "format": "table", + "group": [], + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "metricColumn": "none", + "orderByTime": "ASC", + "policy": "default", + "rawQuery": true, + "rawSql": "select\n top,\n queryid,\n (select data->>'users' from stat_statements where $__timeFilter(time) and dbname = '$dbname' and tag_data->>'queryid' = queryid order by time desc limit 1) as \"Users\",\n query\nfrom (\nselect\n sum(calls - calls_lag)::int8 as top,\n queryid,\n case when length(query) > 200 then query::varchar(200) || '...' else query end as query\nfrom (\n select\n tag_data->>'queryid' as queryid, tag_data->>'query' as query, data->>'users' as users,\n (data->>'calls')::int8 as calls, lag((data->>'calls')::int8) over w as calls_lag,\n time\n from stat_statements\n where dbname = '$dbname'\n and $__timeFilter(time)\n and case when '$hide_pgwatch_generated' = 'yes' then not tag_data->>'query' ~* E'\\\\(extract\\\\(\\\\$\\\\d+\\\\W*from\\\\W*now\\\\(\\\\)\\\\)\\\\W?\\\\*\\\\W*\\\\$\\\\d+\\\\).*::\\\\w+\\\\W+as\\\\W+epoch_ns\\\\W*,'\n and not tag_data->>'query' ~* E'/\\\\*\\\\W*pgwatch_generated\\\\W*\\\\*/' else true end \n window w as (partition by tag_data->>'queryid' order by time)\n) x\nwhere calls > calls_lag\ngroup by 2, 3\norder by 1 desc nulls last\nlimit $top\n) z\norder by 1 desc nulls last", + "refId": "A", + "resultFormat": "table", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Top queries by calls", + "type": "table" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "description": "Does not include Shared Buffer activities. Same as 'By total runtime' if no direct IO was performed. Requires track_io_timing=on", + "fieldConfig": { + "defaults": { + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Time" + }, + "properties": [ + { + "id": "displayName", + "value": "Time" + }, + { + "id": "custom.hidden", + "value": true + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "top" + }, + "properties": [ + { + "id": "displayName", + "value": "IO time" + }, + { + "id": "unit", + "value": "ms" + }, + { + "id": "decimals", + "value": 1 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "queryid" + }, + "properties": [ + { + "id": "displayName", + "value": "Query ID" + }, + { + "id": "unit", + "value": "none" + }, + { + "id": "links", + "value": [ + { + "targetBlank": false, + "title": "Opens 'Single query details' dashboard for that queryid", + "url": "/d/single-query-details?orgId=1&var-dbname=$dbname&var-queryid=$__cell&from=$__from&to=$__to" + } + ] + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "query" + }, + "properties": [ + { + "id": "displayName", + "value": "Query" + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 21 + }, + "id": 8, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "format": "table", + "group": [], + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "metricColumn": "none", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT top(\"spread\", \"queryid\", \"query\", $top) FROM (SELECT spread(\"blk_read_time\") + spread(\"blk_write_time\") AS spread FROM \"stat_statements\" WHERE $timeFilter AND \"dbname\" = '$dbname' GROUP BY time(3650d), \"queryid\", \"query\" fill(none) ) WHERE spread > 0", + "rawQuery": true, + "rawSql": "select\n top,\n queryid,\n (select data->>'users' from stat_statements where $__timeFilter(time) and dbname = '$dbname' and tag_data->>'queryid' = queryid order by time desc limit 1) as \"Users\",\n query\nfrom (\nselect\n sum((wt - wt_lag) + (rt - rt_lag))::int8 as top,\n queryid,\n case when length(query) > 200 then query::varchar(200) || '...' else query end as query\nfrom (\n select\n tag_data->>'queryid' as queryid, tag_data->>'query' as query, data->>'users' as users,\n (data->>'blk_read_time')::float8 as rt, lag((data->>'blk_read_time')::float8) over w as rt_lag,\n (data->>'blk_write_time')::float8 as wt, lag((data->>'blk_write_time')::float8) over w as wt_lag, \n time\n from stat_statements\n where dbname = '$dbname'\n and $__timeFilter(time)\n and case when '$hide_pgwatch_generated' = 'yes' then not tag_data->>'query' ~* E'\\\\(extract\\\\(\\\\$\\\\d+\\\\W*from\\\\W*now\\\\(\\\\)\\\\)\\\\W?\\\\*\\\\W*\\\\$\\\\d+\\\\).*::\\\\w+\\\\W+as\\\\W+epoch_ns\\\\W*,'\n and not tag_data->>'query' ~* E'/\\\\*\\\\W*pgwatch_generated\\\\W*\\\\*/' else true end \n window w as (partition by tag_data->>'queryid' order by time)\n) x\nwhere rt > rt_lag or wt > wt_lag\ngroup by 2, 3\norder by 1 desc nulls last\nlimit $top\n) z\norder by 1 desc nulls last", + "refId": "A", + "resultFormat": "table", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Top queries by direct (backend) IO", + "type": "table" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "description": "Shared buffer + temp buffer reading / writing", + "fieldConfig": { + "defaults": { + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 28 + }, + "id": 10, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "format": "table", + "group": [], + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "metricColumn": "none", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT top(\"spread\", \"queryid\", \"query\", $top) FROM (SELECT spread(\"blk_read_time\") + spread(\"blk_write_time\") AS spread FROM \"stat_statements\" WHERE $timeFilter AND \"dbname\" = '$dbname' GROUP BY time(3650d), \"queryid\", \"query\" fill(none) ) WHERE spread > 0", + "rawQuery": true, + "rawSql": "select\n top,\n queryid,\n (select data->>'users' from stat_statements where $__timeFilter(time) and dbname = '$dbname' and tag_data->>'queryid' = queryid order by time desc limit 1) as \"Users\",\n query\nfrom (\nselect\n sum(blocks_touched - blocks_touched_lag)*8192 /*assuming default 8k block size*/ as top,\n queryid,\n case when length(query) > 200 then query::varchar(200) || '...' else query end as query\nfrom (\n select\n tag_data->>'queryid' as queryid, tag_data->>'query' as query, data->>'users' as users,\n (data->>'shared_blks_hit')::int8 + (data->>'shared_blks_read')::int8 + (data->>'shared_blks_dirtied')::int8 + (data->>'shared_blks_written')::int8\n + (data->>'temp_blks_read')::int8 + (data->>'temp_blks_written')::int8 as blocks_touched,\n lag((data->>'shared_blks_hit')::int8 + (data->>'shared_blks_read')::int8 + (data->>'shared_blks_dirtied')::int8 + (data->>'shared_blks_written')::int8\n + (data->>'temp_blks_read')::int8 + (data->>'temp_blks_written')::int8) over w as blocks_touched_lag,\n time\n from stat_statements\n where dbname = '$dbname'\n and $__timeFilter(time)\n and case when '$hide_pgwatch_generated' = 'yes' then not tag_data->>'query' ~* E'\\\\(extract\\\\(\\\\$\\\\d+\\\\W*from\\\\W*now\\\\(\\\\)\\\\)\\\\W?\\\\*\\\\W*\\\\$\\\\d+\\\\).*::\\\\w+\\\\W+as\\\\W+epoch_ns\\\\W*,'\n and not tag_data->>'query' ~* E'/\\\\*\\\\W*pgwatch_generated\\\\W*\\\\*/' else true end \n window w as (partition by tag_data->>'queryid' order by time)\n) x\nwhere blocks_touched >= blocks_touched_lag\ngroup by 2, 3\nhaving sum(blocks_touched - blocks_touched_lag) > 0\norder by 1 desc nulls last\nlimit $top\n) z\norder by 1 desc nulls last", + "refId": "A", + "resultFormat": "table", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Top by block bandwith (assuming 8K blocks)", + "type": "table" + }, + { + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 35 + }, + "id": 4, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "## Brought to you by\n\n\n \"Cybertec\n", + "mode": "markdown" + }, + "pluginVersion": "12.0.0", + "title": "", + "transparent": true, + "type": "text" + } + ], + "preload": false, + "refresh": "", + "schemaVersion": 41, + "tags": [ + "pgwatch" + ], + "templating": { + "list": [ + { + "current": { + "text": "demo", + "value": "demo" + }, + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "pgwatch-metrics" + }, + "definition": "", + "includeAll": false, + "name": "dbname", + "options": [], + "query": "SELECT DISTINCT dbname FROM admin.all_distinct_dbname_metrics WHERE metric = 'stat_statements' ORDER BY 1;", + "refresh": 1, + "regex": "", + "type": "query" + }, + { + "current": { + "text": "5", + "value": "5" + }, + "includeAll": false, + "name": "top", + "options": [ + { + "selected": false, + "text": "1", + "value": "1" + }, + { + "selected": false, + "text": "3", + "value": "3" + }, + { + "selected": true, + "text": "5", + "value": "5" + }, + { + "selected": false, + "text": "10", + "value": "10" + }, + { + "selected": false, + "text": "15", + "value": "15" + }, + { + "selected": false, + "text": "20", + "value": "20" + }, + { + "selected": false, + "text": "30", + "value": "30" + }, + { + "selected": false, + "text": "40", + "value": "40" + }, + { + "selected": false, + "text": "50", + "value": "50" + } + ], + "query": "1,3,5,10,15,20,30,40,50", + "type": "custom" + }, + { + "current": { + "text": "yes", + "value": "yes" + }, + "includeAll": false, + "name": "hide_pgwatch_generated", + "options": [ + { + "selected": true, + "text": "yes", + "value": "yes" + }, + { + "selected": false, + "text": "no", + "value": "no" + } + ], + "query": "yes,no", + "type": "custom" + } + ] + }, + "time": { + "from": "now-3h", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "Stat statements Top", + "uid": "stat-statements-top", + "version": 3 +} \ No newline at end of file From 4227b3eb67df54944bde906e6cc8c98c2d132481 Mon Sep 17 00:00:00 2001 From: Pavlo Golub Date: Fri, 29 Aug 2025 16:06:40 +0200 Subject: [PATCH 5/8] Fix timeseries panels --- .../postgres/v12/4-query-performance-analysis.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/grafana/postgres/v12/4-query-performance-analysis.json b/grafana/postgres/v12/4-query-performance-analysis.json index 49f4cce758..689bb6aa43 100644 --- a/grafana/postgres/v12/4-query-performance-analysis.json +++ b/grafana/postgres/v12/4-query-performance-analysis.json @@ -498,7 +498,7 @@ }, "format": "time_series", "rawQuery": true, - "rawSql": "-- Top queries by calls over time\nWITH query_calls AS (\n select \n time,\n tag_data->>'queryid' as queryid,\n (data->>'calls')::int8 as calls\n from stat_statements \n where dbname = '$dbname'\n and $__timeFilter(time)\n and case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n),\ntop_queries AS (\n select queryid\n from query_calls\n group by queryid\n order by max(calls) - min(calls) desc\n limit $top\n)\nselect \n time as \"time\",\n calls,\n queryid as metric\nfrom query_calls\nwhere queryid in (select queryid from top_queries)\norder by time", + "rawSql": "-- Top queries by calls over time\nSELECT\n $__timeGroup(time, $agg_interval),\n max((data->>'calls')::int8) - min((data->>'calls')::int8) as calls,\n tag_data->>'queryid' as queryid\nFROM\n stat_statements\nWHERE\n $__timeFilter(time)\n AND dbname = '$dbname'\n AND case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n AND tag_data->>'queryid' IN (\n select tag_data->>'queryid'\n from stat_statements\n where $__timeFilter(time) and dbname = '$dbname'\n and case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n group by tag_data->>'queryid'\n having max((data->>'calls')::int8) - min((data->>'calls')::int8) > 0\n order by max((data->>'calls')::int8) - min((data->>'calls')::int8) desc\n limit $top\n )\nGROUP BY 1, 3\nORDER BY 1", "refId": "A" } ], @@ -598,7 +598,7 @@ }, "format": "time_series", "rawQuery": true, - "rawSql": "-- Top queries by total execution time over time\nWITH query_runtime AS (\n select \n time,\n tag_data->>'queryid' as queryid,\n (data->>'total_time')::numeric as total_time\n from stat_statements \n where dbname = '$dbname'\n and $__timeFilter(time)\n and case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n),\ntop_queries AS (\n select queryid\n from query_runtime\n group by queryid\n order by max(total_time) - min(total_time) desc\n limit $top\n)\nselect \n time as \"time\",\n total_time,\n queryid as metric\nfrom query_runtime\nwhere queryid in (select queryid from top_queries)\norder by time", + "rawSql": "-- Top queries by total execution time over time\nSELECT\n $__timeGroup(time, $agg_interval),\n max((data->>'total_time')::numeric) - min((data->>'total_time')::numeric) as total_time,\n tag_data->>'queryid' as queryid\nFROM\n stat_statements\nWHERE\n $__timeFilter(time)\n AND dbname = '$dbname'\n AND case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n AND tag_data->>'queryid' IN (\n select tag_data->>'queryid'\n from stat_statements\n where $__timeFilter(time) and dbname = '$dbname'\n and case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n group by tag_data->>'queryid'\n having max((data->>'total_time')::numeric) - min((data->>'total_time')::numeric) > 0\n order by max((data->>'total_time')::numeric) - min((data->>'total_time')::numeric) desc\n limit $top\n )\nGROUP BY 1, 3\nORDER BY 1", "refId": "A" } ], @@ -700,7 +700,7 @@ }, "format": "time_series", "rawQuery": true, - "rawSql": "-- Top queries by rows over time\nWITH query_rows AS (\n select \n time,\n tag_data->>'queryid' as queryid,\n (data->>'rows')::int8 as rows\n from stat_statements \n where dbname = '$dbname'\n and $__timeFilter(time)\n and case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n),\ntop_queries AS (\n select queryid\n from query_rows\n group by queryid\n order by max(rows) - min(rows) desc\n limit $top\n)\nselect \n time as \"time\",\n rows,\n queryid as metric\nfrom query_rows\nwhere queryid in (select queryid from top_queries)\norder by time", + "rawSql": "-- Top queries by rows over time\nSELECT\n $__timeGroup(time, $agg_interval),\n max((data->>'rows')::int8) - min((data->>'rows')::int8) as rows,\n tag_data->>'queryid' as queryid\nFROM\n stat_statements\nWHERE\n $__timeFilter(time)\n AND dbname = '$dbname'\n AND case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n AND tag_data->>'queryid' IN (\n select tag_data->>'queryid'\n from stat_statements\n where $__timeFilter(time) and dbname = '$dbname'\n and case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n group by tag_data->>'queryid'\n having max((data->>'rows')::int8) - min((data->>'rows')::int8) > 0\n order by max((data->>'rows')::int8) - min((data->>'rows')::int8) desc\n limit $top\n )\nGROUP BY 1, 3\nORDER BY 1", "refId": "A" } ], @@ -800,7 +800,7 @@ }, "format": "time_series", "rawQuery": true, - "rawSql": "-- Top queries by shared blocks hit over time\nWITH query_shared_hit AS (\n select \n time,\n tag_data->>'queryid' as queryid,\n (data->>'shared_blks_hit')::int8 * 8192 / 1024.0 / 1024.0 as shared_hit_mb\n from stat_statements \n where dbname = '$dbname'\n and $__timeFilter(time)\n and case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n),\ntop_queries AS (\n select queryid\n from query_shared_hit\n group by queryid\n order by max(shared_hit_mb) - min(shared_hit_mb) desc\n limit $top\n)\nselect \n time as \"time\",\n shared_hit_mb,\n queryid as metric\nfrom query_shared_hit\nwhere queryid in (select queryid from top_queries)\norder by time", + "rawSql": "-- Top queries by shared blocks hit over time\nSELECT\n $__timeGroup(time, $agg_interval),\n (max((data->>'shared_blks_hit')::int8) - min((data->>'shared_blks_hit')::int8)) * 8192 / 1024.0 / 1024.0 as shared_hit_mb,\n tag_data->>'queryid' as queryid\nFROM\n stat_statements\nWHERE\n $__timeFilter(time)\n AND dbname = '$dbname'\n AND case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n AND tag_data->>'queryid' IN (\n select tag_data->>'queryid'\n from stat_statements\n where $__timeFilter(time) and dbname = '$dbname'\n and case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n group by tag_data->>'queryid'\n having max((data->>'shared_blks_hit')::int8) - min((data->>'shared_blks_hit')::int8) > 0\n order by (max((data->>'shared_blks_hit')::int8) - min((data->>'shared_blks_hit')::int8)) * 8192 / 1024.0 / 1024.0 desc\n limit $top\n )\nGROUP BY 1, 3\nORDER BY 1", "refId": "A" } ], @@ -902,7 +902,7 @@ }, "format": "time_series", "rawQuery": true, - "rawSql": "-- Top queries by shared blocks read over time\nWITH query_shared_read AS (\n select \n time,\n tag_data->>'queryid' as queryid,\n (data->>'shared_blks_read')::int8 * 8192 / 1024.0 / 1024.0 as shared_read_mb\n from stat_statements \n where dbname = '$dbname'\n and $__timeFilter(time)\n and case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n),\ntop_queries AS (\n select queryid\n from query_shared_read\n group by queryid\n order by max(shared_read_mb) - min(shared_read_mb) desc\n limit $top\n)\nselect \n time as \"time\",\n shared_read_mb,\n queryid as metric\nfrom query_shared_read\nwhere queryid in (select queryid from top_queries)\norder by time", + "rawSql": "-- Top queries by shared blocks read over time\nSELECT\n $__timeGroup(time, $agg_interval),\n (max((data->>'shared_blks_read')::int8) - min((data->>'shared_blks_read')::int8)) * 8192 / 1024.0 / 1024.0 as shared_read_mb,\n tag_data->>'queryid' as queryid\nFROM\n stat_statements\nWHERE\n $__timeFilter(time)\n AND dbname = '$dbname'\n AND case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n AND tag_data->>'queryid' IN (\n select tag_data->>'queryid'\n from stat_statements\n where $__timeFilter(time) and dbname = '$dbname'\n and case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n group by tag_data->>'queryid'\n having max((data->>'shared_blks_read')::int8) - min((data->>'shared_blks_read')::int8) > 0\n order by (max((data->>'shared_blks_read')::int8) - min((data->>'shared_blks_read')::int8)) * 8192 / 1024.0 / 1024.0 desc\n limit $top\n )\nGROUP BY 1, 3\nORDER BY 1", "refId": "A" } ], @@ -1002,7 +1002,7 @@ }, "format": "time_series", "rawQuery": true, - "rawSql": "-- Top queries by temp blocks read over time\nWITH query_temp_read AS (\n select \n time,\n tag_data->>'queryid' as queryid,\n (data->>'temp_blks_read')::int8 * 8192 / 1024.0 / 1024.0 as temp_read_mb\n from stat_statements \n where dbname = '$dbname'\n and $__timeFilter(time)\n and case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n),\ntop_queries AS (\n select queryid\n from query_temp_read\n group by queryid\n order by max(temp_read_mb) - min(temp_read_mb) desc\n limit $top\n)\nselect \n time as \"time\",\n temp_read_mb,\n queryid as metric\nfrom query_temp_read\nwhere queryid in (select queryid from top_queries)\nand temp_read_mb > 0\norder by time", + "rawSql": "-- Top queries by temp blocks read over time\nSELECT\n $__timeGroup(time, $agg_interval),\n (max((data->>'temp_blks_read')::int8) - min((data->>'temp_blks_read')::int8)) * 8192 / 1024.0 / 1024.0 as temp_read_mb,\n tag_data->>'queryid' as queryid\nFROM\n stat_statements\nWHERE\n $__timeFilter(time)\n AND dbname = '$dbname'\n AND case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n AND tag_data->>'queryid' IN (\n select tag_data->>'queryid'\n from stat_statements\n where $__timeFilter(time) and dbname = '$dbname'\n and case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n group by tag_data->>'queryid'\n having max((data->>'temp_blks_read')::int8) - min((data->>'temp_blks_read')::int8) > 0\n order by (max((data->>'temp_blks_read')::int8) - min((data->>'temp_blks_read')::int8)) * 8192 / 1024.0 / 1024.0 desc\n limit $top\n )\nGROUP BY 1, 3\nORDER BY 1", "refId": "A" } ], @@ -1104,7 +1104,7 @@ }, "format": "time_series", "rawQuery": true, - "rawSql": "-- Top queries by temp blocks written over time\nWITH query_temp_written AS (\n select \n time,\n tag_data->>'queryid' as queryid,\n (data->>'temp_blks_written')::int8 * 8192 / 1024.0 / 1024.0 as temp_written_mb\n from stat_statements \n where dbname = '$dbname'\n and $__timeFilter(time)\n and case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n),\ntop_queries AS (\n select queryid\n from query_temp_written\n group by queryid\n order by max(temp_written_mb) - min(temp_written_mb) desc\n limit $top\n)\nselect \n time as \"time\",\n temp_written_mb,\n queryid as metric\nfrom query_temp_written\nwhere queryid in (select queryid from top_queries)\nand temp_written_mb > 0\norder by time", + "rawSql": "-- Top queries by temp blocks written over time\nSELECT\n $__timeGroup(time, $agg_interval),\n (max((data->>'temp_blks_written')::int8) - min((data->>'temp_blks_written')::int8)) * 8192 / 1024.0 / 1024.0 as temp_written_mb,\n tag_data->>'queryid' as queryid\nFROM\n stat_statements\nWHERE\n $__timeFilter(time)\n AND dbname = '$dbname'\n AND case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n AND tag_data->>'queryid' IN (\n select tag_data->>'queryid'\n from stat_statements\n where $__timeFilter(time) and dbname = '$dbname'\n and case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n group by tag_data->>'queryid'\n having max((data->>'temp_blks_written')::int8) - min((data->>'temp_blks_written')::int8) > 0\n order by (max((data->>'temp_blks_written')::int8) - min((data->>'temp_blks_written')::int8)) * 8192 / 1024.0 / 1024.0 desc\n limit $top\n )\nGROUP BY 1, 3\nORDER BY 1", "refId": "A" } ], From 8259b20dde8f4a3e305d917a26d24ad86e920fb1 Mon Sep 17 00:00:00 2001 From: Pavlo Golub Date: Fri, 29 Aug 2025 16:20:37 +0200 Subject: [PATCH 6/8] remove realtime panels --- .../postgres/v12/stat-activity-realtime.json | 311 ------------------ grafana/postgres/v12/stat-activity.json | 300 ----------------- 2 files changed, 611 deletions(-) delete mode 100644 grafana/postgres/v12/stat-activity-realtime.json delete mode 100644 grafana/postgres/v12/stat-activity.json diff --git a/grafana/postgres/v12/stat-activity-realtime.json b/grafana/postgres/v12/stat-activity-realtime.json deleted file mode 100644 index 506a583ee7..0000000000 --- a/grafana/postgres/v12/stat-activity-realtime.json +++ /dev/null @@ -1,311 +0,0 @@ -{ - "annotations": { - "list": [ - { - "builtIn": 1, - "datasource": { - "type": "datasource", - "uid": "grafana" - }, - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "type": "dashboard" - } - ] - }, - "editable": true, - "fiscalYearStartMonth": 0, - "graphTooltip": 0, - "id": 24, - "links": [], - "panels": [ - { - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "description": "Top 25 longest running queries from pg_stat_activity. Query texts are compacted", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "custom": { - "align": "auto", - "cellOptions": { - "type": "auto" - }, - "inspect": false - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "pid" - }, - "properties": [ - { - "id": "unit", - "value": "short" - }, - { - "id": "decimals", - "value": 2 - }, - { - "id": "custom.align" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "duration" - }, - "properties": [ - { - "id": "unit", - "value": "s" - }, - { - "id": "decimals", - "value": 1 - }, - { - "id": "custom.cellOptions", - "value": { - "type": "color-text" - } - }, - { - "id": "custom.align" - }, - { - "id": "thresholds", - "value": { - "mode": "absolute", - "steps": [ - { - "color": "rgba(50, 172, 45, 0.97)" - }, - { - "color": "rgba(237, 129, 40, 0.89)", - "value": 60 - }, - { - "color": "rgba(245, 54, 54, 0.9)", - "value": 300 - } - ] - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "waiting" - }, - "properties": [ - { - "id": "unit", - "value": "short" - }, - { - "id": "decimals", - "value": 2 - }, - { - "id": "custom.cellOptions", - "value": { - "type": "color-text" - } - }, - { - "id": "custom.align" - }, - { - "id": "thresholds", - "value": { - "mode": "absolute", - "steps": [ - { - "color": "rgba(50, 172, 45, 0.97)" - }, - { - "color": "#C4162A", - "value": 1 - }, - { - "color": "rgba(245, 54, 54, 0.9)", - "value": 2 - } - ] - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "blocking_pids" - }, - "properties": [ - { - "id": "unit", - "value": "short" - }, - { - "id": "decimals", - "value": 2 - }, - { - "id": "custom.align" - } - ] - } - ] - }, - "gridPos": { - "h": 24, - "w": 24, - "x": 0, - "y": 0 - }, - "id": 2, - "options": { - "cellHeight": "sm", - "footer": { - "countRows": false, - "fields": "", - "reducer": [ - "sum" - ], - "show": false - }, - "showHeader": true - }, - "pluginVersion": "12.0.0", - "targets": [ - { - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "format": "table", - "group": [], - "metricColumn": "none", - "rawQuery": true, - "rawSql": "SELECT\n tag_data->>'pid' AS pid,\n data->>'user' AS user,\n data->>'appname' AS appname,\n data->>'ip' AS ip,\n (data->>'duration_s')::int AS duration,\n data->>'waiting' AS waiting,\n coalesce(data->>'blocking_pids', '') AS blocking_pids,\n data->>'query' AS query\nFROM\n stat_activity_realtime\nWHERE\n dbname = '$dbname'\n AND time = (SELECT max(time) FROM stat_activity_realtime WHERE dbname = '$dbname' AND $__timeFilter(time))\n AND (data->>'duration_s')::int > $min_duration_s\nORDER BY\n duration DESC\nLIMIT 25\n\n\n\n\n\n\n\n\n\n\n\n\n", - "refId": "A", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "column" - } - ] - ], - "timeColumn": "time", - "where": [ - { - "name": "$__timeFilter", - "params": [], - "type": "macro" - } - ] - } - ], - "title": "Stat Activity", - "transformations": [ - { - "id": "merge", - "options": { - "reducers": [] - } - } - ], - "type": "table" - } - ], - "preload": false, - "refresh": "5s", - "schemaVersion": 41, - "tags": [ - "pgwatch" - ], - "templating": { - "list": [ - { - "current": { - "text": "", - "value": "" - }, - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "definition": "SELECT DISTINCT dbname FROM admin.all_distinct_dbname_metrics WHERE metric = 'stat_activity_realtime' ORDER BY 1;", - "includeAll": false, - "name": "dbname", - "options": [], - "query": "SELECT DISTINCT dbname FROM admin.all_distinct_dbname_metrics WHERE metric = 'stat_activity_realtime' ORDER BY 1;", - "refresh": 1, - "regex": "", - "type": "query" - }, - { - "current": { - "text": "1", - "value": "1" - }, - "name": "min_duration_s", - "options": [ - { - "selected": true, - "text": "1", - "value": "1" - } - ], - "query": "1", - "type": "textbox" - } - ] - }, - "time": { - "from": "now-5m", - "to": "now" - }, - "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m" - ] - }, - "timezone": "", - "title": "Stat Activity Realtime", - "uid": "stat-activity-realtime", - "version": 11 -} \ No newline at end of file diff --git a/grafana/postgres/v12/stat-activity.json b/grafana/postgres/v12/stat-activity.json deleted file mode 100644 index 3fddf8f4b5..0000000000 --- a/grafana/postgres/v12/stat-activity.json +++ /dev/null @@ -1,300 +0,0 @@ -{ - "annotations": { - "list": [ - { - "builtIn": 1, - "datasource": { - "type": "datasource", - "uid": "grafana" - }, - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "type": "dashboard" - } - ] - }, - "editable": true, - "fiscalYearStartMonth": 0, - "graphTooltip": 0, - "id": 32, - "links": [], - "panels": [ - { - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "description": "Top 25 longest running queries from pg_stat_activity. Query texts are compacted", - "fieldConfig": { - "defaults": { - "custom": { - "align": "auto", - "cellOptions": { - "type": "auto" - }, - "inspect": false - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "pid" - }, - "properties": [ - { - "id": "unit", - "value": "short" - }, - { - "id": "decimals", - "value": 2 - }, - { - "id": "custom.align" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "duration" - }, - "properties": [ - { - "id": "unit", - "value": "s" - }, - { - "id": "decimals", - "value": 1 - }, - { - "id": "custom.cellOptions", - "value": { - "type": "color-text" - } - }, - { - "id": "custom.align" - }, - { - "id": "thresholds", - "value": { - "mode": "absolute", - "steps": [ - { - "color": "rgba(50, 172, 45, 0.97)" - }, - { - "color": "rgba(237, 129, 40, 0.89)", - "value": 60 - }, - { - "color": "rgba(245, 54, 54, 0.9)", - "value": 300 - } - ] - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "waiting" - }, - "properties": [ - { - "id": "unit", - "value": "short" - }, - { - "id": "decimals", - "value": 2 - }, - { - "id": "custom.cellOptions", - "value": { - "type": "color-text" - } - }, - { - "id": "custom.align" - }, - { - "id": "thresholds", - "value": { - "mode": "absolute", - "steps": [ - { - "color": "rgba(50, 172, 45, 0.97)" - }, - { - "color": "#C4162A", - "value": 1 - }, - { - "color": "rgba(245, 54, 54, 0.9)", - "value": 2 - } - ] - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "blocking_pids" - }, - "properties": [ - { - "id": "unit", - "value": "short" - }, - { - "id": "decimals", - "value": 2 - }, - { - "id": "custom.align" - } - ] - } - ] - }, - "gridPos": { - "h": 24, - "w": 24, - "x": 0, - "y": 0 - }, - "id": 2, - "options": { - "cellHeight": "sm", - "footer": { - "countRows": false, - "fields": "", - "reducer": [ - "sum" - ], - "show": false - }, - "showHeader": true - }, - "pluginVersion": "12.0.0", - "targets": [ - { - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "format": "table", - "group": [], - "metricColumn": "none", - "rawQuery": true, - "rawSql": "SELECT\n tag_data->>'pid' AS pid,\n data->>'user' AS user,\n data->>'appname' AS appname,\n data->>'ip' AS ip,\n (data->>'duration_s')::int AS duration,\n data->>'waiting' AS waiting,\n coalesce(data->>'blocking_pids', '') AS blocking_pids,\n data->>'query' AS query\nFROM\n stat_activity_realtime\nWHERE\n dbname = '$dbname'\n AND time = (SELECT max(time) FROM stat_activity_realtime WHERE dbname = '$dbname' AND $__timeFilter(time))\n AND (data->>'duration_s')::int > $min_duration_s\nORDER BY\n duration DESC\nLIMIT 25\n\n\n\n\n\n\n\n\n\n\n\n\n", - "refId": "A", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "column" - } - ] - ], - "timeColumn": "time", - "where": [ - { - "name": "$__timeFilter", - "params": [], - "type": "macro" - } - ] - } - ], - "title": "Stat Activity", - "type": "table" - } - ], - "preload": false, - "refresh": "5s", - "schemaVersion": 41, - "tags": [ - "pgwatch" - ], - "templating": { - "list": [ - { - "current": { - "text": "", - "value": "" - }, - "datasource": { - "type": "grafana-postgresql-datasource", - "uid": "pgwatch-metrics" - }, - "definition": "SELECT DISTINCT dbname FROM admin.all_distinct_dbname_metrics WHERE metric = 'stat_activity_realtime' ORDER BY 1;", - "includeAll": false, - "name": "dbname", - "options": [], - "query": "SELECT DISTINCT dbname FROM admin.all_distinct_dbname_metrics WHERE metric = 'stat_activity_realtime' ORDER BY 1;", - "refresh": 1, - "regex": "", - "type": "query" - }, - { - "current": { - "text": "1", - "value": "1" - }, - "name": "min_duration_s", - "options": [ - { - "selected": true, - "text": "1", - "value": "1" - } - ], - "query": "1", - "type": "textbox" - } - ] - }, - "time": { - "from": "now-5m", - "to": "now" - }, - "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m" - ] - }, - "timezone": "", - "title": "Stat Activity", - "uid": "stat-activity", - "version": 11 -} \ No newline at end of file From 411e6751c902c06a69d52c42e3ebabed904658b9 Mon Sep 17 00:00:00 2001 From: Pavlo Golub Date: Fri, 29 Aug 2025 16:28:15 +0200 Subject: [PATCH 7/8] add agg_interval var --- .../v12/4-query-performance-analysis.json | 58 ++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/grafana/postgres/v12/4-query-performance-analysis.json b/grafana/postgres/v12/4-query-performance-analysis.json index 689bb6aa43..11bab0e013 100644 --- a/grafana/postgres/v12/4-query-performance-analysis.json +++ b/grafana/postgres/v12/4-query-performance-analysis.json @@ -1242,6 +1242,62 @@ ], "query": "!pgwatch_generated,.*,!SELECT,UPDATE|DELETE|INSERT", "type": "custom" + }, + { + "auto": false, + "auto_count": 30, + "auto_min": "10s", + "current": { + "text": "5m", + "value": "5m" + }, + "label": "Aggregate Interval", + "name": "agg_interval", + "options": [ + { + "selected": true, + "text": "5m", + "value": "5m" + }, + { + "selected": false, + "text": "10m", + "value": "10m" + }, + { + "selected": false, + "text": "15m", + "value": "15m" + }, + { + "selected": false, + "text": "30m", + "value": "30m" + }, + { + "selected": false, + "text": "1h", + "value": "1h" + }, + { + "selected": false, + "text": "6h", + "value": "6h" + }, + { + "selected": false, + "text": "12h", + "value": "12h" + }, + { + "selected": false, + "text": "1d", + "value": "1d" + } + ], + "query": "5m,10m,15m,30m,1h,6h,12h,1d", + "refresh": 2, + "type": "interval" } ] }, @@ -1253,5 +1309,5 @@ "timezone": "browser", "title": "4. Query Performance Analysis", "uid": "query-performance-analysis", - "version": 4 + "version": 49 } \ No newline at end of file From a74ca5aafcee82a6e26eae68a70f6035d20747f2 Mon Sep 17 00:00:00 2001 From: Pavlo Golub Date: Fri, 29 Aug 2025 16:42:03 +0200 Subject: [PATCH 8/8] use fully regex-driven filter --- .../v12/4-query-performance-analysis.json | 37 +++++++++++-------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/grafana/postgres/v12/4-query-performance-analysis.json b/grafana/postgres/v12/4-query-performance-analysis.json index 11bab0e013..68ddfda6bd 100644 --- a/grafana/postgres/v12/4-query-performance-analysis.json +++ b/grafana/postgres/v12/4-query-performance-analysis.json @@ -383,7 +383,7 @@ }, "format": "table", "rawQuery": true, - "rawSql": "-- Enhanced comprehensive query analysis (Fast mode)\nWITH query_stats AS (\n select\n tag_data->>'queryid' as queryid,\n max((data->>'total_time')::numeric) - min((data->>'total_time')::numeric) as total_runtime,\n (max((data->>'total_time')::numeric) - min((data->>'total_time')::numeric)) / nullif(max((data->>'calls')::int8) - min((data->>'calls')::int8), 0) as avg_runtime,\n max((data->>'total_plan_time')::numeric) - min((data->>'total_plan_time')::numeric) as plan_time,\n (max((data->>'total_plan_time')::numeric) - min((data->>'total_plan_time')::numeric)) / nullif(max((data->>'calls')::int8) - min((data->>'calls')::int8), 0) as avg_plan_time,\n max((data->>'calls')::int8) - min((data->>'calls')::int8) as calls,\n max((data->>'rows')::int8) - min((data->>'rows')::int8) as rows,\n (max((data->>'rows')::int8) - min((data->>'rows')::int8))::numeric / nullif(max((data->>'calls')::int8) - min((data->>'calls')::int8), 0) as avg_rows,\n (max((data->>'shared_blks_hit')::int8) - min((data->>'shared_blks_hit')::int8)) * 8192 / 1024.0 / 1024.0 as shared_hit_mb,\n (max((data->>'shared_blks_read')::int8) - min((data->>'shared_blks_read')::int8)) * 8192 / 1024.0 / 1024.0 as shared_read_mb,\n (max((data->>'shared_blks_written')::int8) - min((data->>'shared_blks_written')::int8)) * 8192 / 1024.0 / 1024.0 as shared_written_mb,\n (max((data->>'temp_blks_read')::int8) - min((data->>'temp_blks_read')::int8)) * 8192 / 1024.0 / 1024.0 as temp_read_mb,\n (max((data->>'temp_blks_written')::int8) - min((data->>'temp_blks_written')::int8)) * 8192 / 1024.0 / 1024.0 as temp_written_mb,\n (max((data->>'blk_read_time')::numeric) - min((data->>'blk_read_time')::numeric)) + \n (max((data->>'blk_write_time')::numeric) - min((data->>'blk_write_time')::numeric)) as io_time,\n case when length(tag_data->>'query') > 150 then (tag_data->>'query')::varchar(150) || '...' else tag_data->>'query' end as query\n from stat_statements\n where dbname = '$dbname'\n and $__timeFilter(time)\n and case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n group by tag_data->>'queryid', tag_data->>'query'\n having max((data->>'calls')::int8) - min((data->>'calls')::int8) > 0\n),\nwith_percentages AS (\n select \n *,\n 100 * total_runtime / nullif((select sum(total_runtime) from query_stats), 0) as pct_db_total\n from query_stats\n)\nselect\n queryid,\n total_runtime::int8 as \"Total Runtime (ms)\",\n avg_runtime::numeric(10,2) as \"Avg Runtime (ms)\",\n plan_time::int8 as \"Plan Time (ms)\",\n avg_plan_time::numeric(10,2) as \"Avg Plan Time (ms)\",\n calls as \"Calls\",\n rows as \"Rows\",\n avg_rows::numeric(10,1) as \"Avg Rows\",\n shared_hit_mb::numeric(10,1) as \"Shared Hit (MB)\",\n shared_read_mb::numeric(10,1) as \"Shared Read (MB)\",\n shared_written_mb::numeric(10,1) as \"Shared Written (MB)\",\n temp_read_mb::numeric(10,1) as \"Temp Read (MB)\",\n temp_written_mb::numeric(10,1) as \"Temp Written (MB)\",\n io_time::numeric(10,1) as \"IO Time (ms)\",\n pct_db_total::numeric(5,1) as \"% DB Total\",\n (select data->>'users' from stat_statements where $__timeFilter(time) and dbname = '$dbname' and tag_data->>'queryid' = with_percentages.queryid order by time desc limit 1) as \"Users\",\n query as \"Query\"\nfrom with_percentages\norder by total_runtime desc nulls last\nlimit $top", + "rawSql": "-- Enhanced comprehensive query analysis (Fast mode)\nWITH query_stats AS (\n select\n tag_data->>'queryid' as queryid,\n max((data->>'total_time')::numeric) - min((data->>'total_time')::numeric) as total_runtime,\n (max((data->>'total_time')::numeric) - min((data->>'total_time')::numeric)) / nullif(max((data->>'calls')::int8) - min((data->>'calls')::int8), 0) as avg_runtime,\n max((data->>'total_plan_time')::numeric) - min((data->>'total_plan_time')::numeric) as plan_time,\n (max((data->>'total_plan_time')::numeric) - min((data->>'total_plan_time')::numeric)) / nullif(max((data->>'calls')::int8) - min((data->>'calls')::int8), 0) as avg_plan_time,\n max((data->>'calls')::int8) - min((data->>'calls')::int8) as calls,\n max((data->>'rows')::int8) - min((data->>'rows')::int8) as rows,\n (max((data->>'rows')::int8) - min((data->>'rows')::int8))::numeric / nullif(max((data->>'calls')::int8) - min((data->>'calls')::int8), 0) as avg_rows,\n (max((data->>'shared_blks_hit')::int8) - min((data->>'shared_blks_hit')::int8)) * 8192 / 1024.0 / 1024.0 as shared_hit_mb,\n (max((data->>'shared_blks_read')::int8) - min((data->>'shared_blks_read')::int8)) * 8192 / 1024.0 / 1024.0 as shared_read_mb,\n (max((data->>'shared_blks_written')::int8) - min((data->>'shared_blks_written')::int8)) * 8192 / 1024.0 / 1024.0 as shared_written_mb,\n (max((data->>'temp_blks_read')::int8) - min((data->>'temp_blks_read')::int8)) * 8192 / 1024.0 / 1024.0 as temp_read_mb,\n (max((data->>'temp_blks_written')::int8) - min((data->>'temp_blks_written')::int8)) * 8192 / 1024.0 / 1024.0 as temp_written_mb,\n (max((data->>'blk_read_time')::numeric) - min((data->>'blk_read_time')::numeric)) + \n (max((data->>'blk_write_time')::numeric) - min((data->>'blk_write_time')::numeric)) as io_time,\n case when length(tag_data->>'query') > 150 then (tag_data->>'query')::varchar(150) || '...' else tag_data->>'query' end as query\n from stat_statements\n where dbname = '$dbname'\n and $__timeFilter(time)\n and tag_data->>'query' ~* '$query_filter_regex'\n group by tag_data->>'queryid', tag_data->>'query'\n having max((data->>'calls')::int8) - min((data->>'calls')::int8) > 0\n),\nwith_percentages AS (\n select \n *,\n 100 * total_runtime / nullif((select sum(total_runtime) from query_stats), 0) as pct_db_total\n from query_stats\n)\nselect\n queryid,\n total_runtime::int8 as \"Total Runtime (ms)\",\n avg_runtime::numeric(10,2) as \"Avg Runtime (ms)\",\n plan_time::int8 as \"Plan Time (ms)\",\n avg_plan_time::numeric(10,2) as \"Avg Plan Time (ms)\",\n calls as \"Calls\",\n rows as \"Rows\",\n avg_rows::numeric(10,1) as \"Avg Rows\",\n shared_hit_mb::numeric(10,1) as \"Shared Hit (MB)\",\n shared_read_mb::numeric(10,1) as \"Shared Read (MB)\",\n shared_written_mb::numeric(10,1) as \"Shared Written (MB)\",\n temp_read_mb::numeric(10,1) as \"Temp Read (MB)\",\n temp_written_mb::numeric(10,1) as \"Temp Written (MB)\",\n io_time::numeric(10,1) as \"IO Time (ms)\",\n pct_db_total::numeric(5,1) as \"% DB Total\",\n (select data->>'users' from stat_statements where $__timeFilter(time) and dbname = '$dbname' and tag_data->>'queryid' = with_percentages.queryid order by time desc limit 1) as \"Users\",\n query as \"Query\"\nfrom with_percentages\norder by total_runtime desc nulls last\nlimit $top", "refId": "A" } ], @@ -498,7 +498,7 @@ }, "format": "time_series", "rawQuery": true, - "rawSql": "-- Top queries by calls over time\nSELECT\n $__timeGroup(time, $agg_interval),\n max((data->>'calls')::int8) - min((data->>'calls')::int8) as calls,\n tag_data->>'queryid' as queryid\nFROM\n stat_statements\nWHERE\n $__timeFilter(time)\n AND dbname = '$dbname'\n AND case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n AND tag_data->>'queryid' IN (\n select tag_data->>'queryid'\n from stat_statements\n where $__timeFilter(time) and dbname = '$dbname'\n and case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n group by tag_data->>'queryid'\n having max((data->>'calls')::int8) - min((data->>'calls')::int8) > 0\n order by max((data->>'calls')::int8) - min((data->>'calls')::int8) desc\n limit $top\n )\nGROUP BY 1, 3\nORDER BY 1", + "rawSql": "-- Top queries by calls over time\nSELECT\n $__timeGroup(time, $agg_interval),\n max((data->>'calls')::int8) - min((data->>'calls')::int8) as calls,\n tag_data->>'queryid' as queryid\nFROM\n stat_statements\nWHERE\n $__timeFilter(time)\n AND dbname = '$dbname'\n AND tag_data->>'query' ~* '$query_filter_regex'\n AND tag_data->>'queryid' IN (\n select tag_data->>'queryid'\n from stat_statements\n where $__timeFilter(time) and dbname = '$dbname'\n and tag_data->>'query' ~* '$query_filter_regex'\n group by tag_data->>'queryid'\n having max((data->>'calls')::int8) - min((data->>'calls')::int8) > 0\n order by max((data->>'calls')::int8) - min((data->>'calls')::int8) desc\n limit $top\n )\nGROUP BY 1, 3\nORDER BY 1", "refId": "A" } ], @@ -598,7 +598,7 @@ }, "format": "time_series", "rawQuery": true, - "rawSql": "-- Top queries by total execution time over time\nSELECT\n $__timeGroup(time, $agg_interval),\n max((data->>'total_time')::numeric) - min((data->>'total_time')::numeric) as total_time,\n tag_data->>'queryid' as queryid\nFROM\n stat_statements\nWHERE\n $__timeFilter(time)\n AND dbname = '$dbname'\n AND case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n AND tag_data->>'queryid' IN (\n select tag_data->>'queryid'\n from stat_statements\n where $__timeFilter(time) and dbname = '$dbname'\n and case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n group by tag_data->>'queryid'\n having max((data->>'total_time')::numeric) - min((data->>'total_time')::numeric) > 0\n order by max((data->>'total_time')::numeric) - min((data->>'total_time')::numeric) desc\n limit $top\n )\nGROUP BY 1, 3\nORDER BY 1", + "rawSql": "-- Top queries by total execution time over time\nSELECT\n $__timeGroup(time, $agg_interval),\n max((data->>'total_time')::numeric) - min((data->>'total_time')::numeric) as total_time,\n tag_data->>'queryid' as queryid\nFROM\n stat_statements\nWHERE\n $__timeFilter(time)\n AND dbname = '$dbname'\n AND tag_data->>'query' ~* '$query_filter_regex'\n AND tag_data->>'queryid' IN (\n select tag_data->>'queryid'\n from stat_statements\n where $__timeFilter(time) and dbname = '$dbname'\n and tag_data->>'query' ~* '$query_filter_regex'\n group by tag_data->>'queryid'\n having max((data->>'total_time')::numeric) - min((data->>'total_time')::numeric) > 0\n order by max((data->>'total_time')::numeric) - min((data->>'total_time')::numeric) desc\n limit $top\n )\nGROUP BY 1, 3\nORDER BY 1", "refId": "A" } ], @@ -700,7 +700,7 @@ }, "format": "time_series", "rawQuery": true, - "rawSql": "-- Top queries by rows over time\nSELECT\n $__timeGroup(time, $agg_interval),\n max((data->>'rows')::int8) - min((data->>'rows')::int8) as rows,\n tag_data->>'queryid' as queryid\nFROM\n stat_statements\nWHERE\n $__timeFilter(time)\n AND dbname = '$dbname'\n AND case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n AND tag_data->>'queryid' IN (\n select tag_data->>'queryid'\n from stat_statements\n where $__timeFilter(time) and dbname = '$dbname'\n and case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n group by tag_data->>'queryid'\n having max((data->>'rows')::int8) - min((data->>'rows')::int8) > 0\n order by max((data->>'rows')::int8) - min((data->>'rows')::int8) desc\n limit $top\n )\nGROUP BY 1, 3\nORDER BY 1", + "rawSql": "-- Top queries by rows over time\nSELECT\n $__timeGroup(time, $agg_interval),\n max((data->>'rows')::int8) - min((data->>'rows')::int8) as rows,\n tag_data->>'queryid' as queryid\nFROM\n stat_statements\nWHERE\n $__timeFilter(time)\n AND dbname = '$dbname'\n AND tag_data->>'query' ~* '$query_filter_regex'\n AND tag_data->>'queryid' IN (\n select tag_data->>'queryid'\n from stat_statements\n where $__timeFilter(time) and dbname = '$dbname'\n and tag_data->>'query' ~* '$query_filter_regex'\n group by tag_data->>'queryid'\n having max((data->>'rows')::int8) - min((data->>'rows')::int8) > 0\n order by max((data->>'rows')::int8) - min((data->>'rows')::int8) desc\n limit $top\n )\nGROUP BY 1, 3\nORDER BY 1", "refId": "A" } ], @@ -800,7 +800,7 @@ }, "format": "time_series", "rawQuery": true, - "rawSql": "-- Top queries by shared blocks hit over time\nSELECT\n $__timeGroup(time, $agg_interval),\n (max((data->>'shared_blks_hit')::int8) - min((data->>'shared_blks_hit')::int8)) * 8192 / 1024.0 / 1024.0 as shared_hit_mb,\n tag_data->>'queryid' as queryid\nFROM\n stat_statements\nWHERE\n $__timeFilter(time)\n AND dbname = '$dbname'\n AND case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n AND tag_data->>'queryid' IN (\n select tag_data->>'queryid'\n from stat_statements\n where $__timeFilter(time) and dbname = '$dbname'\n and case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n group by tag_data->>'queryid'\n having max((data->>'shared_blks_hit')::int8) - min((data->>'shared_blks_hit')::int8) > 0\n order by (max((data->>'shared_blks_hit')::int8) - min((data->>'shared_blks_hit')::int8)) * 8192 / 1024.0 / 1024.0 desc\n limit $top\n )\nGROUP BY 1, 3\nORDER BY 1", + "rawSql": "-- Top queries by shared blocks hit over time\nSELECT\n $__timeGroup(time, $agg_interval),\n (max((data->>'shared_blks_hit')::int8) - min((data->>'shared_blks_hit')::int8)) * 8192 / 1024.0 / 1024.0 as shared_hit_mb,\n tag_data->>'queryid' as queryid\nFROM\n stat_statements\nWHERE\n $__timeFilter(time)\n AND dbname = '$dbname'\n AND tag_data->>'query' ~* '$query_filter_regex'\n AND tag_data->>'queryid' IN (\n select tag_data->>'queryid'\n from stat_statements\n where $__timeFilter(time) and dbname = '$dbname'\n and tag_data->>'query' ~* '$query_filter_regex'\n group by tag_data->>'queryid'\n having max((data->>'shared_blks_hit')::int8) - min((data->>'shared_blks_hit')::int8) > 0\n order by (max((data->>'shared_blks_hit')::int8) - min((data->>'shared_blks_hit')::int8)) * 8192 / 1024.0 / 1024.0 desc\n limit $top\n )\nGROUP BY 1, 3\nORDER BY 1", "refId": "A" } ], @@ -902,7 +902,7 @@ }, "format": "time_series", "rawQuery": true, - "rawSql": "-- Top queries by shared blocks read over time\nSELECT\n $__timeGroup(time, $agg_interval),\n (max((data->>'shared_blks_read')::int8) - min((data->>'shared_blks_read')::int8)) * 8192 / 1024.0 / 1024.0 as shared_read_mb,\n tag_data->>'queryid' as queryid\nFROM\n stat_statements\nWHERE\n $__timeFilter(time)\n AND dbname = '$dbname'\n AND case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n AND tag_data->>'queryid' IN (\n select tag_data->>'queryid'\n from stat_statements\n where $__timeFilter(time) and dbname = '$dbname'\n and case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n group by tag_data->>'queryid'\n having max((data->>'shared_blks_read')::int8) - min((data->>'shared_blks_read')::int8) > 0\n order by (max((data->>'shared_blks_read')::int8) - min((data->>'shared_blks_read')::int8)) * 8192 / 1024.0 / 1024.0 desc\n limit $top\n )\nGROUP BY 1, 3\nORDER BY 1", + "rawSql": "-- Top queries by shared blocks read over time\nSELECT\n $__timeGroup(time, $agg_interval),\n (max((data->>'shared_blks_read')::int8) - min((data->>'shared_blks_read')::int8)) * 8192 / 1024.0 / 1024.0 as shared_read_mb,\n tag_data->>'queryid' as queryid\nFROM\n stat_statements\nWHERE\n $__timeFilter(time)\n AND dbname = '$dbname'\n AND tag_data->>'query' ~* '$query_filter_regex'\n AND tag_data->>'queryid' IN (\n select tag_data->>'queryid'\n from stat_statements\n where $__timeFilter(time) and dbname = '$dbname'\n and tag_data->>'query' ~* '$query_filter_regex'\n group by tag_data->>'queryid'\n having max((data->>'shared_blks_read')::int8) - min((data->>'shared_blks_read')::int8) > 0\n order by (max((data->>'shared_blks_read')::int8) - min((data->>'shared_blks_read')::int8)) * 8192 / 1024.0 / 1024.0 desc\n limit $top\n )\nGROUP BY 1, 3\nORDER BY 1", "refId": "A" } ], @@ -1002,7 +1002,7 @@ }, "format": "time_series", "rawQuery": true, - "rawSql": "-- Top queries by temp blocks read over time\nSELECT\n $__timeGroup(time, $agg_interval),\n (max((data->>'temp_blks_read')::int8) - min((data->>'temp_blks_read')::int8)) * 8192 / 1024.0 / 1024.0 as temp_read_mb,\n tag_data->>'queryid' as queryid\nFROM\n stat_statements\nWHERE\n $__timeFilter(time)\n AND dbname = '$dbname'\n AND case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n AND tag_data->>'queryid' IN (\n select tag_data->>'queryid'\n from stat_statements\n where $__timeFilter(time) and dbname = '$dbname'\n and case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n group by tag_data->>'queryid'\n having max((data->>'temp_blks_read')::int8) - min((data->>'temp_blks_read')::int8) > 0\n order by (max((data->>'temp_blks_read')::int8) - min((data->>'temp_blks_read')::int8)) * 8192 / 1024.0 / 1024.0 desc\n limit $top\n )\nGROUP BY 1, 3\nORDER BY 1", + "rawSql": "-- Top queries by temp blocks read over time\nSELECT\n $__timeGroup(time, $agg_interval),\n (max((data->>'temp_blks_read')::int8) - min((data->>'temp_blks_read')::int8)) * 8192 / 1024.0 / 1024.0 as temp_read_mb,\n tag_data->>'queryid' as queryid\nFROM\n stat_statements\nWHERE\n $__timeFilter(time)\n AND dbname = '$dbname'\n AND tag_data->>'query' ~* '$query_filter_regex'\n AND tag_data->>'queryid' IN (\n select tag_data->>'queryid'\n from stat_statements\n where $__timeFilter(time) and dbname = '$dbname'\n and tag_data->>'query' ~* '$query_filter_regex'\n group by tag_data->>'queryid'\n having max((data->>'temp_blks_read')::int8) - min((data->>'temp_blks_read')::int8) > 0\n order by (max((data->>'temp_blks_read')::int8) - min((data->>'temp_blks_read')::int8)) * 8192 / 1024.0 / 1024.0 desc\n limit $top\n )\nGROUP BY 1, 3\nORDER BY 1", "refId": "A" } ], @@ -1104,7 +1104,7 @@ }, "format": "time_series", "rawQuery": true, - "rawSql": "-- Top queries by temp blocks written over time\nSELECT\n $__timeGroup(time, $agg_interval),\n (max((data->>'temp_blks_written')::int8) - min((data->>'temp_blks_written')::int8)) * 8192 / 1024.0 / 1024.0 as temp_written_mb,\n tag_data->>'queryid' as queryid\nFROM\n stat_statements\nWHERE\n $__timeFilter(time)\n AND dbname = '$dbname'\n AND case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n AND tag_data->>'queryid' IN (\n select tag_data->>'queryid'\n from stat_statements\n where $__timeFilter(time) and dbname = '$dbname'\n and case \n when '$query_filter_regex' like '!%' then not tag_data->>'query' ~* substring('$query_filter_regex' from 2)\n else tag_data->>'query' ~* '$query_filter_regex' \n end\n group by tag_data->>'queryid'\n having max((data->>'temp_blks_written')::int8) - min((data->>'temp_blks_written')::int8) > 0\n order by (max((data->>'temp_blks_written')::int8) - min((data->>'temp_blks_written')::int8)) * 8192 / 1024.0 / 1024.0 desc\n limit $top\n )\nGROUP BY 1, 3\nORDER BY 1", + "rawSql": "-- Top queries by temp blocks written over time\nSELECT\n $__timeGroup(time, $agg_interval),\n (max((data->>'temp_blks_written')::int8) - min((data->>'temp_blks_written')::int8)) * 8192 / 1024.0 / 1024.0 as temp_written_mb,\n tag_data->>'queryid' as queryid\nFROM\n stat_statements\nWHERE\n $__timeFilter(time)\n AND dbname = '$dbname'\n AND tag_data->>'query' ~* '$query_filter_regex'\n AND tag_data->>'queryid' IN (\n select tag_data->>'queryid'\n from stat_statements\n where $__timeFilter(time) and dbname = '$dbname'\n and tag_data->>'query' ~* '$query_filter_regex'\n group by tag_data->>'queryid'\n having max((data->>'temp_blks_written')::int8) - min((data->>'temp_blks_written')::int8) > 0\n order by (max((data->>'temp_blks_written')::int8) - min((data->>'temp_blks_written')::int8)) * 8192 / 1024.0 / 1024.0 desc\n limit $top\n )\nGROUP BY 1, 3\nORDER BY 1", "refId": "A" } ], @@ -1214,15 +1214,15 @@ "text": ".*", "value": ".*" }, - "description": "Custom regex filter for queries. Use '!' prefix to exclude, e.g., '!pgwatch_generated' excludes queries containing 'pgwatch_generated'. Use regular expressions like 'SELECT|INSERT' to include only specific patterns.", + "description": "Custom regex filter for queries. Examples: '.*' (all queries), '^(?!.*pgwatch_generated)' (exclude pgwatch_generated), '(SELECT|INSERT)' (include only SELECT/INSERT), '^(?!.*(SELECT|INSERT))' (exclude SELECT/INSERT), 'UPDATE.*^(?!.*WHERE)' (dangerous UPDATEs without WHERE - security risk).", "includeAll": false, "label": "Filter RegEx", "name": "query_filter_regex", "options": [ { "selected": false, - "text": "!pgwatch_generated", - "value": "!pgwatch_generated" + "text": "^(?!.*pgwatch_generated)", + "value": "^(?!.*pgwatch_generated)" }, { "selected": true, @@ -1231,16 +1231,21 @@ }, { "selected": false, - "text": "!SELECT", - "value": "!SELECT" + "text": "^(?!.*SELECT)", + "value": "^(?!.*SELECT)" }, { "selected": false, - "text": "UPDATE|DELETE|INSERT", - "value": "UPDATE|DELETE|INSERT" + "text": "(UPDATE|DELETE|INSERT)", + "value": "(UPDATE|DELETE|INSERT)" + }, + { + "selected": false, + "text": "UPDATE.*^(?!.*WHERE)", + "value": "UPDATE.*^(?!.*WHERE)" } ], - "query": "!pgwatch_generated,.*,!SELECT,UPDATE|DELETE|INSERT", + "query": "^(?!.*pgwatch_generated),.*,^(?!.*SELECT),(UPDATE|DELETE|INSERT),UPDATE.*^(?!.*WHERE)", "type": "custom" }, {