POSETTE
2026
· 26 min
SyncGrid 3
Traces why SELECT * FROM customers WHERE state='CA' on a 1M-row table with an index still seq-scans, by reading pg_stats columns n_distinct, null_frac, correlation, most_common_vals/most_common_freqs, and histogram_bounds, then fixing bad estimates with ALTER TABLE ... ALTER COLUMN ... SET STATISTICS 1000 and CREATE STATISTICS. pg_stats is a human-readable view over table pg_statistic; Postgres naming trivia — plural/stat names are views, singular are tables. ANALYZE populates it. n_distinct = -1 means every value unique (primary key). correlation near 0 = data randomly spread on disk, pushes planner to seq scan; near ±1 favors index scan. CA at 17.4% frequency, TX 11.65%: seq scan cost 19,000, est 17,000 rows vs 17,200 actual. Wyoming (4,000 rows) picks index scan at cost 13,000. Forcing SET enable_seqscan=off on the CA query yields index scan costing 32,000 — confirming planner chose correctly. Costs driven by random_page_cost, seq_page_cost, cpu_tuple_cost. Default 100 histogram buckets ≈ 2 months per bucket on signup_date; 1000 buckets ≈ 2 days, max 10,000 — tradeoff is slower ANALYZE, so raise per column only. Multi-column correlation: city='Cheyenne' AND state='WY' estimates 8 rows vs 4,012 actual because planner multiplies independent probabilities; CREATE STATISTICS ... (dependencies, ndistinct) + ANALYZE brings estimate to 4,087. Six-step debug recipe: compare estimated vs actual rows at deepest EXPLAIN ANALYZE node, inspect pg_stats, re-ANALYZE after batch loads/migrations when autovacuum lags, raise statistics target, add extended statistics, then rewrite query.
SyncGrid: Steal CREATE STATISTICS dependencies for correlated tenant/meter columns; rest is known planner basics.