Fix bad row estimates with extended statistics
When two columns are correlated the planner multiplies their selectivities and guesses badly. CREATE STATISTICS teaches it the dependency, a ~1,250-row guess becomes ~10,000 against 10,000 actual.
Problem
What you're actually looking at
The symptom as it shows up on a real server.
By default PostgreSQL assumes columns are independent. When they are correlated (a town always maps to one postal area), it multiplies selectivities and under-estimates matching rows by orders of magnitude, which produces the wrong join and scan strategy.
Meridian's depot_routes table has origin_town and postal_area that move together. Filtering on both, the planner under-estimates badly until extended statistics teach it the dependency.
Simple terms
Before running a query the planner guesses how many rows a filter will match, and by default it assumes each column is independent of the others. When two columns actually move together, a town always sits inside one postal area, it multiplies their odds as if they were unrelated and badly under-counts the matches. That wrong guess leads it to pick the wrong plan. CREATE STATISTICS tells PostgreSQL the two columns are linked, so its estimate lines up with what the query really returns.
Full runbook for this incident
- The full identify checklist, the exact signals that tell you it's this incident
- Every diagnostic query; lab output is attached only to the steps we actually captured
- The resolution path and the pitfalls that make it worse
- Mitigation steps to stop it recurring, plus a verify-you're-done query
Card required. Cancel before day 7 and you are not charged.
More in this category
Other Query performance runbooks
Neighbouring incidents that share the same diagnostic surface.
Need the full procedure?
Pro runbooks finish the incident path
Free runbooks teach the shape. Pro opens the full step transcript, edge cases, and prevention depth.