Index Advisor on managed PostgreSQL
Find the indexes your PostgreSQL queries are missing.
Index Advisor watches your real workload and shows the evidence for every index it suggests and every one it would drop. It never changes your database: you copy the SQL and run it when you choose.
shop-db
PostgreSQL 17 · ap-south-1
Index Advisor
On by default for new databases. Recommendations only: nothing is created or dropped for you. Watching database "shop".
Based on 214 statements observed (38 analysed), 30 Oct 22:56 to 22:56.
Data
486 MB
6 tables
Indexes
212 MB
8 indexes
Writes
38 / min
Measured over the last 60 min
Reclaimable
9.4 MB
From indexes suggested for removal
Add an index on public.orders (customer_id)
Filtered by equality on customer_id.
Add an index on public.orders (created_at)
Filtered by a range on created_at.
Add an index on public.orders (customer_id)
Filtered by equality on customer_id.
public.orders (about 1,204,377 rows) is filtered on customer_id and no existing index serves that.
Recommended index
CREATE INDEX CONCURRENTLY "selfhost_idx_orders_5c1e9a07" ON "public"."orders" ("customer_id");Run it yourself in a quiet moment. CREATE INDEX CONCURRENTLY does not block writes but takes longer, cannot run inside a transaction and if it fails it leaves an invalid index holding its space (drop it and retry).
Index Advisor never runs this for you.
Why this is recommended
We observed 48,213 calls filtering on orders.customer_id in the analysed period. The current plan reads the table with Seq Scan, which reads more rows than needed.
High confidence: with a hypothetical copy of the index, the query planner chose it and its estimated cost fell 99% (a planner estimate, not measured time).
Est. 26 MB to 31 MB: an estimate, not a measurement, from PostgreSQL's B-tree page layout applied to the table's statistics (rows, column widths), never its data.
Index Advisor is off
It was turned off for this database, so nothing is collected or analysed. pg_stat_statements stays installed, so turning it on again needs no restart.
Index Advisor settings
Changes apply from the next collection
Database
The database whose queries and tables are analysed: the one your application uses.
Hypothetical index checks (HypoPG)
Installs the HypoPG extension on every node of this database (a few minutes, no restart) and checks each proposal with a hypothetical index. Off: proposals are still checked against the current plan.
History kept
Hourly detail is kept for two days, then one sample a day.
Stops collection and analysis for this database. pg_stat_statements stays installed (removing it would restart PostgreSQL and the Queries tab uses it). Your settings and past findings are kept and it stays off until you turn it on again.
A replica of the console's Index Advisor tab with its own words, on a sample database. In the console nothing here creates or drops an index: Copy SQL is the only way a statement leaves the tab.
On by default
On from the first query.
Your call on older databases.
Often an index advisor is an extension to install and a function to call, one query at a time. Here it watches the whole workload of every new PostgreSQL database from day one.
On from the start
Every managed PostgreSQL database created from scratch since 27 October 2026 has Index Advisor on. pg_stat_statements is installed before PostgreSQL first starts, so nothing restarts. The first collection follows within the hour.
One switch, your call
An owner or admin turns it on from the Index Advisor tab. If the database already loads pg_stat_statements, nothing restarts. If it does not, PostgreSQL restarts once (a few seconds, open connections dropped) and only after you confirm.
Off whenever you like
Turning it off stops collection and analysis for that database. pg_stat_statements stays installed, so turning it on again needs no restart. Your settings and past findings are kept.
What it finds
Indexes to add.
Indexes to drop.
Each finding carries a confidence label with what it rests on, an estimated impact for ordering and, for a new index, a size range estimated from statistics, with a warning when the build may not fit on the disk.
Missing indexes
Statements that filter, sort under a LIMIT or join on columns no index serves, ranked by estimated impact.
Unused indexes
Indexes not scanned once over the days observed, still costing storage and work on every write.
Duplicate indexes
Two indexes with the same definition. One of the two is enough.
Redundant indexes
An index whose columns another index already leads with.
Invalid indexes
Indexes left invalid by a failed build for at least a day, still holding their space.
Already served or not an index
When an existing index already serves a statement or an index is not the answer, it says so instead of guessing.
How it decides
Every suggestion
shows its working.
- 1
Collect, every hour
A light look each hour reads pg_stat_statements (how often each statement ran and how long it took) plus table and index statistics. A full look runs once a day. Each database has its own minute of the hour, so collections are spread out.
- 2
Analyse, every day
Once a day it reads the workload for statements that filter, sort or join on columns no index serves and for indexes nothing uses. Analyse now runs one sooner, up to three times a day per database.
- 3
Check with the planner
Each proposal is checked against the statement's query plan. With hypothetical index checks on (HypoPG, one setting, no restart) the planner is asked whether it would use the index and how far its cost estimate falls. Nothing is built and no statement is run.
- 4
You decide
Copy the CREATE INDEX CONCURRENTLY statement and run it in a quiet moment from psql or your migration tool. Or dismiss the finding for 30 days or mark it as seen.
A worked example
-- 1. What pg_stat_statements kept: the shape, values as $1, $2
SELECT id, status, total, created_at
FROM orders
WHERE customer_id = $1
ORDER BY created_at DESC LIMIT $2
-- 41,833 calls, 41.7 ms on average
-- 2. What Index Advisor concluded
Add an index on public.orders (customer_id)
High confidence: with a hypothetical copy of the
index, the query planner chose it and its estimated
cost fell 99% (a planner estimate, not measured time).
Today: Seq Scan, cost 25,413
With the index: Index Scan, cost 98.7
-- 3. What you copy and run yourself, in a quiet moment
CREATE INDEX CONCURRENTLY "selfhost_idx_orders_5c1e9a07"
ON "public"."orders" ("customer_id"); Costs are planner units, not milliseconds: the tab says so next to its numbers. CREATE INDEX CONCURRENTLY does not block writes; it cannot run inside a transaction, so run it on its own from psql or a migration that allows it. The console's SQL editor is read-only, so it is the place to check the plan with EXPLAIN, not to build the index.
What it reads
Statistics in.
Your rows never.
- ✓pg_stat_statements: how often each statement ran and how long it took
- ✓Each statement's shape only: PostgreSQL's own parser turns every value into a parameter and cuts comments out. A statement that still holds a value keeps no text at all
- ✓Table and index statistics: sizes, scans, row estimates and column widths
- ✓The planner's cost estimate for a statement, with a hypothetical index when HypoPG is on
- ×Reads your rows: size estimates come from statistics, never from your data
- ×Runs your statements to test them: the planner estimates, nothing executes
- ×Creates, drops or changes an index for you
- ×Restarts your database without your confirmation
Careful about drops
Slow to suggest a drop.
Never on the indexes that matter.
An index that looks unused may still serve a monthly report, so Index Advisor waits a long time before it says so. It never flags the indexes your keys and constraints depend on.
- ●Never flagged as unused: primary keys, unique and constraint indexes, indexes under 1 MB.
- ●Unused indexes are judged only after 7 days and 5 daily collections.
- ●Removal is suggested only after 35 days and 25 daily collections, longer than a monthly job's month. Until then an unused index is marked for review.
- ●When statistics are reset or the database restarts, observation starts again, so a fresh window never reads as unused.
- ●Reads on replicas are not counted, so on a database with replicas removal is never suggested.
- ●Every drop statement comes with a reminder to check that no rare job, report or replica needs the index.
Before you rely on it
Six things we would
want to know first.
Careful by design still has edges. None of them should surprise you after the first analysis, so here they are up front.
- 1 PostgreSQL only. Other engines, ClickHouse included, do not have Index Advisor.
- 2 One database per instance is watched: the one your application uses, set in Settings. Changing it starts observation again.
- 3 Costs are planner estimates in planner units and sizes are ranges. It never promises a measured speed-up.
- 4 On a very large database the busiest statements and tables are read and the tab says so.
- 5 Owners and admins turn it on, change its settings and see the findings, because findings name your tables and queries.
- 6 History is kept 14, 40, 60 or 90 days (40 by default). Under 35 days, unused indexes are only marked for review.
Next to Index Advisor
Find it, check it,
ship it yourself.
Frequently asked questions
Does Index Advisor create indexes automatically?
Is it on for my database?
Will turning it on restart my database?
Does it read my data?
Which databases does it support?
How often does it analyse?
Does it work on read replicas?
Does it cost anything?
The index your query needs.
On from the first day.
Start a PostgreSQL database
$5 in free credit, no card needed.