Skip to main content
Metrics type: Key MetricsCategory: Performance

At a glance

The percentage of database queries in the window that exceeded the slow-query threshold. This is the single best early-warning signal that the database is starting to struggle: it rises before latency averages move and well before users complain. A handful of slow queries is normal under any real workload; a rising slow-query rate means an index is missing, a plan has regressed, a table has bloated, or load has outgrown the instance. For an ops team, this card answers “what share of my queries are too slow right now, and is that share growing?”

Calculation

The rate is a ratio of slow executions to total executions over the rolling window:
where a “slow execution” is any query whose runtime exceeded the slow threshold (default 1000ms). The numerator and denominator come from pg_stat_statements, the Postgres extension that aggregates execution statistics per normalised query (queries are normalised so that WHERE id = 1 and WHERE id = 2 collapse into one entry with id = $1). For each statement entry, pg_stat_statements tracks calls (total executions) and timing fields (total_exec_time, mean_exec_time, max_exec_time). The engine takes deltas between successive snapshots so the rate reflects only activity within the 15-minute window rather than lifetime totals. Because pg_stat_statements records mean and max but not a full duration histogram per statement, the engine combines two signals for accuracy:
  1. Statement-level estimate from pg_stat_statements: statements whose mean exceeds the threshold contribute their full call count to the slow bucket.
  2. Log-derived count from the database log, where log_min_duration_statement writes one line per individual statement that crossed the threshold. This captures the case of an otherwise-fast statement that was slow on a specific execution (a cold cache, a lock wait, a bad parameter value hitting a skewed index).
The two are reconciled so the rate reflects actual slow executions, not just statements with a slow average. The 5% alert threshold is the point at which slow queries stop being background noise and start materially degrading the experience for normal traffic: at 5%, one in twenty queries is dragging, which is already visible in p95 latency and connection-hold time.

Worked example

A B2B platform team runs a Supabase project backing a customer-facing dashboard. Normal slow-query rate sits at 0.3%. On 22 May 26, a product release added a new “activity feed” panel that queries an events table. Snapshot taken at 16:20 BST, 40 minutes after the release. The Nerve Centre headline shows 7.8% on the gauge, in the red zone, alert tripped (threshold 5%). Reading the situation:
  1. The rate jumped 26x with no change in total volume. Traffic is flat (~205k executions), so this is not a load spike. Something is now structurally slow. The release is the obvious suspect.
  2. The new activity-feed query is unindexed. Drilling into Top 10 Slowest Queries shows a single statement, SELECT * FROM events WHERE user_id = $1 ORDER BY created_at DESC LIMIT 50, accounting for nearly all the slow executions. It is doing a sequential scan of a 12-million-row table on every dashboard load because there is no index on user_id.
What the team should do:
  1. Add the missing index. CREATE INDEX CONCURRENTLY idx_events_user_created ON events (user_id, created_at DESC); turns the sequential scan into an index scan. The slow-query rate should drop back toward baseline within one 15-minute window once the index is built.
  2. Confirm the fix with the rate, not a spot check. Re-running one query by hand may hit a warm cache and look fine. The rate over the next window is the honest signal that the problem is gone for all traffic.
  3. Check the knock-on metrics drain too. Supavisor Pool Saturation % and Postgres Query Latency p95 (ms) should both recover as connections stop being held open by the slow scan.
The lesson: slow-query rate is the leading indicator. It moved the moment the bad query shipped, before users filed tickets and before the average latency looked alarming. Watching this card after every release catches index regressions in minutes rather than days.

Sibling cards to reference together

Reconciling against the source

Where to look in Supabase and Postgres:
Supabase project Query Performance / Reports section for the built-in slow-query view, which surfaces pg_stat_statements ranked by total and mean time. SELECT query, calls, mean_exec_time, max_exec_time FROM pg_stat_statements WHERE mean_exec_time > 1000 ORDER BY total_exec_time DESC; for the authoritative server-side list of slow statements. SELECT calls, total_exec_time FROM pg_stat_statements; aggregated for the denominator (total executions). The database log (filtered on log_min_duration_statement) for individual slow-execution lines, which catch one-off slow runs that the mean hides.
Why our number may legitimately differ from a hand-run query: The cleanest reconciliation is to take two pg_stat_statements snapshots 15 minutes apart, diff the calls and slow-bucket counts, and compute the ratio yourself. That delta-based number should track this card closely.

Known limitations / FAQs

What counts as “slow”? Can I change the threshold? The default is 1000ms (one second). Supabase exposes log_min_duration_statement and related settings per project; lowering it (say to 500ms) makes the card stricter and surfaces moderately slow queries earlier. Raising it hides them. Pick a threshold that matches your latency budget: a real-time dashboard might set 200ms, a reporting workload might tolerate 5000ms. The 5% alert applies to whatever threshold you configure. My rate is 0% but the dashboard feels slow. Two possibilities. First, your slow threshold may be set higher than the latency users actually notice: if it is 1000ms but users feel pain at 300ms, queries in the 300 to 1000ms band are “fast” by the card’s definition but slow to humans. Lower the threshold. Second, the bottleneck may not be query duration at all: connection-pool waits, network latency to the client, or front-end rendering can make a fast database feel slow. Check Supavisor Pool Saturation %. Why does the rate move before average latency does? Because it is a ratio of count, not a duration average. A burst of slow queries immediately shifts the slow/total ratio, whereas an average is diluted by all the fast queries around it. One bad query shape can push the rate from 0.3% to 8% while only nudging the mean by a few milliseconds. That sensitivity is exactly why this is the leading indicator. Does a stats reset break the card? No. Running pg_stat_statements_reset() zeroes the lifetime counters, but this card works from deltas between successive snapshots, so after the next snapshot it resumes correctly. The only effect is that the very next reading after a reset may be based on a short partial window. Do timeouts count as slow queries? A statement that runs up to the statement_timeout and is then aborted has, by definition, exceeded almost any slow threshold, so it counts in the slow bucket and may also count in Database Query Error Rate % as an error. Seeing both rates rise together is the classic timeout signature. The rate is high but Top 10 Slowest Queries looks normal. The Top 10 table ranks by total or mean time over its own window (24h). A short, sharp burst of slowness inside the last 15 minutes can spike the rate without yet dominating the 24-hour Top 10. Trust the rate for “is it happening now” and the Top 10 for “what has been costing the most over the day”. If the rate stays high, the offending query will climb the Top 10 within a few hours. Does PgBouncer / Supavisor pooling affect the count? No. The rate is measured at the Postgres layer from pg_stat_statements, which records every executed statement regardless of how it arrived (through the transaction pooler, the session pooler, a direct connection, or PostgREST). Pooling changes how connections are reused, not which queries execute.

Tracked live in Vortex IQ Nerve Centre

Slow-Query Rate % is one of hundreds of KPI pulses Vortex IQ tracks across Supabase and 70+ other ecommerce connectors. Nerve Centre runs the detection layer; Vortex Mind investigates the cause when something moves; Ask Viq lets you interrogate any number in plain English. Start for free or book a demo to see this metric running on your own data.