PostgreSQL Statistics & The Planner: How Data Drives Query Plans
Learning Objectives: By the end of this lesson, you will be able to:
- Explain how PostgreSQL collects and uses statistics for query planning
- Use the
ANALYZEcommand and interpret thepg_statisticandpg_statstables- Identify and fix issues caused by outdated or inaccurate statistics
1. Welcome and Introduction (5 minutes)
Icebreaker Activity
Have you ever wondered why PostgreSQL sometimes makes a bad choice for a query plan, even when you have the right indexes? Today, you’ll learn how the database “sees” your data and how you can help it make better decisions!
Lesson Overview
- Duration: 90 minutes
- Prerequisites: Completed Days 1-3, basic understanding of query plans and I/O
- Materials Needed: PostgreSQL database, SQL client
2. Learning Objectives and Session Outline (5 minutes)
What We’ll Cover Today:
- What are statistics in PostgreSQL?
- How the planner uses statistics to choose query plans
- Using
ANALYZE,pg_statistic, andpg_stats - How bad statistics lead to bad plans
- Hands-on practice and exercises
- Common pitfalls and troubleshooting
Success Criteria:
By the end of this session, you should be able to update and interpret statistics, and recognize when statistics are causing poor query plans.
3. Foundation Knowledge (15-20 minutes)
Core Concepts
What Are Statistics in PostgreSQL?
Statistics are metadata about your tables: how many rows, value distributions, most common values, and more. The planner uses these to estimate how many rows a query will process.
Real-World Analogy: Imagine planning a trip with a map that shows traffic patterns. If your map is outdated, you might get stuck in traffic. PostgreSQL’s planner relies on up-to-date statistics to avoid “traffic jams” in query plans.
Why This Matters:
- Accurate statistics help the planner choose the best plan
- Outdated or missing statistics can lead to slow queries
The ANALYZE Command
- Collects statistics for a table or database
- Should be run after large data changes
- Autovacuum usually runs it automatically, but you can run it manually
The pg_statistic and pg_stats Tables
pg_statistic: Internal table with detailed stats (not user-friendly)pg_stats: View for human-readable statistics (one row per column)- Shows histograms, most common values (MCV), null fraction, and more
Key Terminology
- Histogram: Distribution of values in a column
- MCV (Most Common Values): Most frequent values in a column
- Correlation: How ordered the data is (affects index usage)
- Autovacuum: Background process that runs
ANALYZEandVACUUM
4. Detailed Explanation and Examples (25-30 minutes)
How the Planner Uses Statistics
The planner estimates how many rows each step will process. It uses statistics to decide:
- Whether to use an index or a sequential scan
- Which join method to use
- How much memory to allocate for sorts and hashes
Practical Applications
- Run
ANALYZEafter bulk inserts, updates, or deletes - Check
pg_statsto see if statistics match your data - Use statistics to diagnose bad query plans
Common Misconceptions
- Misconception: “Statistics are only about row counts.” Reality: PostgreSQL tracks value distributions, nulls, and more.
- Misconception: “Autovacuum always keeps stats up to date.”
Reality: Heavy data churn or large bulk loads may require manual
ANALYZE.
5. Live Coding Demonstration (20-25 minutes)
Example 1: Viewing Statistics
-- See stats for a table
SELECT * FROM pg_stats WHERE tablename = 'users';
Explanation:
- Shows null fraction, most common values, histogram, and more for each column
Example 2: Running ANALYZE
-- Update statistics for a table
ANALYZE users;
- Should be run after significant data changes
Example 3: Bad Estimates from Outdated Stats
-- Change a lot of data
UPDATE users SET status = 'inactive';
-- Run a query and check the plan
EXPLAIN ANALYZE SELECT * FROM users WHERE status = 'active';
-- Now update stats
ANALYZE users;
EXPLAIN ANALYZE SELECT * FROM users WHERE status = 'active';
- The first plan may have bad row estimates; after ANALYZE, estimates should improve
Debugging Demonstration
Show how to spot bad estimates:
-- Look for big differences between estimated and actual rows
EXPLAIN ANALYZE SELECT * FROM users WHERE email LIKE '%@gmail.com';
6. Hands-On Practice (30-40 minutes)
Exercise 1: Basic Practice (10 minutes)
Objective: View and interpret statistics for a table
Instructions:
- Pick a table in your database
- Run
SELECT * FROM pg_stats WHERE tablename = 'your_table'; - Note the null fraction, most common values, and histogram for key columns
Starter Code:
SELECT * FROM pg_stats WHERE tablename = 'your_table';
Solution:
-- Example output (truncated)
attname | null_frac | n_distinct | most_common_vals | histogram_bounds
--------+-----------+------------+------------------+-----------------
status | 0.01 | -0.5 | {active,inactive}| {active,deleted}
Exercise 2: Intermediate Challenge (15 minutes)
Objective: See how changing data affects statistics and query plans
Requirements:
- Update a large portion of a table
- Run a query and check the plan
- Run
ANALYZEand check the plan again
Hints:
- Use
UPDATEorINSERTto change data - Look for changes in estimated vs. actual rows
Exercise 3: Creative Application (15 minutes)
Objective: Experiment with statistics and planner decisions
Challenge:
- Create a table with skewed data (e.g., 90% of rows have the same value)
- Run queries and observe planner estimates
- Try
CREATE STATISTICSfor multi-column stats (PostgreSQL 10+)
Extension Ideas:
- Explore how correlation affects index usage
- Try with different data distributions
7. Common Pitfalls and Troubleshooting (10 minutes)
Frequent Mistakes
-
Problem: Not running
ANALYZEafter bulk data changes Cause: Planner uses outdated statistics Solution: RunANALYZEmanually after large changes -
Problem: Misinterpreting statistics in
pg_statsCause: Not understanding MCVs, histograms, or correlation Solution: Review documentation and experiment with sample data
Debugging Tips
- Always check estimated vs. actual rows in query plans
- Use
ANALYZEto refresh stats after big data changes - Use
pg_statsfor a human-readable view of statistics
8. Best Practices and Professional Tips (5 minutes)
Industry Standards
- Monitor and update statistics regularly
- Use
CREATE STATISTICSfor multi-column dependencies (PostgreSQL 10+) - Document when and why you run manual
ANALYZE
Next Steps in Your Learning Journey
- Learn about planner settings and overrides (see Day 5)
- Explore advanced statistics features
- Practice with real-world data and query plans
9. Summary and Review (5 minutes)
Key Takeaways
- Statistics drive the planner’s decisions
- Outdated or inaccurate stats can cause bad query plans
- Use
ANALYZEandpg_statsto keep and check stats
Quick Review Questions
- What does the
ANALYZEcommand do? - How can you view statistics for a table?
- Why do bad statistics lead to bad query plans?
For Instructors
Teaching Tips
- Demonstrate with tables before and after running
ANALYZE - Show how planner estimates change with data distribution
- Use real-world examples of bad plans caused by stats
Assessment Ideas
- Have students interpret
pg_statsoutput - Ask students to fix a bad plan by updating statistics
- Peer review: students explain how stats affect a sample plan
Adaptation Notes
- For beginners: focus on running
ANALYZEand readingpg_stats - For advanced students: include multi-column stats and correlation
- Online: use screen sharing to show live stats and plan changes