To find indexes that have not been used since the last statistics reset with pg_stat_reset(), run this on your production server:
SELECT u.schemaname, u.relname AS tablename, u.indexrelname AS indexname, pg_relation_size(u.indexrelid) AS index_size FROM pg_catalog.pg_stat_user_indexes u JOIN pg_catalog.pg_index i ON u.indexrelid = i.indexrelid WHERE u.idx_scan = 0 -- never been scanned AND 0 <> ALL (i.indkey) -- no index column is an expression AND NOT EXISTS -- index not used to enforce a constraint (SELECT 1 FROM pg_catalog.pg_constraint c WHERE c.conindid = u.indexrelid) ORDER BY pg_relation_size(u.indexrelid) DESC;
Indexes that are very rarely used can also be good candidates for removal; replace u.idx_scan = 0 in the query with a different threshold, e.g. u.idx_scan < 5. BUT be aware of indexes whose purpose is to support queries which are run infrequently such as monthly reporting queries.
And, always script out your indexes before you remove them.
Further useful index scripts can be found here.