Supabase query performance: finding and tracking slow queries
If you're on Supabase, you already have a Query Performance view in the dashboard (under Advisors → Query Performance). It lists your slowest queries by cumulative execution time, with call counts — and for "what's hammering my database right now?", it's genuinely enough.
It's powered by pg_stat_statements, the
Postgres extension Supabase ships preinstalled. Understanding what that view
can and can't do is the key to not getting surprised by a slow query in
production.
Make sure pg_stat_statements is enabled
Supabase has the extension available but not always toggled on. In the SQL
editor (connected as postgres):
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
Then read the slowest queries directly — this is essentially what the dashboard tab runs:
SELECT
query,
calls,
round(mean_exec_time::numeric, 1) AS avg_ms,
round(total_exec_time::numeric, 0) AS total_ms
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 20;
Sort by total_exec_time (cumulative cost), not mean_exec_time — a 5ms query
called a million times hurts more than a 2s query called twice.
Reading it without a superuser
Don't point monitoring at the postgres superuser. Supabase keeps
pg_stat_statements in the extensions schema, so a read-only role needs
pg_monitor plus USAGE on that schema:
CREATE ROLE pgblame_reader WITH LOGIN PASSWORD '<choose-something-strong>';
GRANT pg_monitor TO pgblame_reader; -- includes pg_read_all_stats
GRANT USAGE ON SCHEMA extensions TO pgblame_reader;
GRANT CONNECT ON DATABASE postgres TO pgblame_reader;
(The full walkthrough, including the pooler-host and username gotchas, is in the Supabase setup docs.)
The Query Performance tab — and the raw view — only ever show you now. Cumulative
totals since the last stats reset, with no history and no link to your
deploys (only Supabase's platform events). So when a query that used to be 40ms
is suddenly 800ms, the dashboard can tell you it's slow, but not that it
changed, when, or which deploy was live. You'd have to have been snapshotting
pg_stat_statements yourself, on a schedule, to answer that.
Tracking it over time
That snapshot-over-time job is what pgblame automates. The agent reads
pg_stat_statements every 60 seconds and stores per-query deltas; your Vercel
or Railway deploys land on the same timeline via a webhook. The result is a
"Since last deploy" view that turns "is this slow?" into "this got slow after
this deploy."
It's the same data Supabase's tab reads — just kept over time and joined to your releases, on a stack that doesn't have to be Rails (compare pganalyze at 8× the price).
See which deploy slowed your Postgres — free, no card.
Start free — no cardFAQ
- Where is Query Performance in Supabase?
- Supabase dashboard → Advisors → Query Performance (also reachable from the Reports area). It's backed by the pg_stat_statements extension, which Supabase ships preinstalled.
- Does Supabase Query Performance show history?
- No. It shows current cumulative stats from pg_stat_statements. There's no built-in trend over time and no link to your application deploys — only Supabase platform events. For 'was this always slow or did my deploy break it?', you need snapshots over time.
- What role does pgblame need on Supabase?
- A read-only role with pg_monitor (which includes pg_read_all_stats) plus USAGE on the extensions schema, since Supabase keeps pg_stat_statements there. Full SQL is in the Supabase setup docs.
- Will monitoring slow my Supabase database?
- No meaningfully. Reading pg_stat_statements is one cheap SELECT against a system view; pgblame's agent runs it once every 60 seconds with a short statement timeout.