Fix bad row estimates with CREATE STATISTICS
The planner assumes columns are independent. When city and postcode are correlated, it multiplies their selectivities and estimates far too few rows, then picks a nested loop that takes minutes.
CREATE STATISTICS addr_stats (dependencies) ON city, postcode FROM addresses;
ANALYZE addresses;Look for plans where the estimated rows are off by a factor of ten or more. That gap is almost always a correlation the planner cannot see.
postgresqlperformance