Common Query Patterns & Their Plans in PostgreSQL

Learning Objectives: By the end of this lesson, you will be able to:

  • Recognize typical query plan shapes for common SQL operations
  • Predict how PostgreSQL will plan simple WHERE, JOIN, GROUP BY, ORDER BY, and LIMIT queries
  • Analyze and optimize these patterns using EXPLAIN ANALYZE

1. Welcome and Introduction (5 minutes)

Icebreaker Activity

What is the most common type of query you run in your applications? Have you ever wondered why some simple queries are fast, while others are unexpectedly slow? Today, you’ll learn to recognize the “shapes” of common query plans and what they mean for performance!

Lesson Overview

  • Duration: 90 minutes
  • Prerequisites: Completed Days 1-5, basic SQL and query plan knowledge
  • Materials Needed: PostgreSQL database, SQL client

2. Learning Objectives and Session Outline (5 minutes)

What We’ll Cover Today:

  1. Typical query patterns in real-world applications
  2. How PostgreSQL plans simple WHERE queries
  3. Plans for JOIN, GROUP BY, ORDER BY, and LIMIT
  4. Hands-on practice and exercises
  5. Common pitfalls and troubleshooting

Success Criteria:

By the end of this session, you should be able to write and analyze common query patterns, and understand their performance implications.

3. Foundation Knowledge (15-20 minutes)

Core Concepts

What Are Query Patterns?

Query patterns are recurring types of SQL queries that appear in most applications. Each pattern tends to produce a characteristic plan shape in PostgreSQL.

Real-World Analogy: Think of query patterns like common routes on a map—some are highways (fast, direct), others are back roads (slower, more stops). Recognizing the route helps you predict travel time.

Why This Matters:

  • Helps you anticipate performance issues
  • Guides index and schema design
  • Makes query tuning more systematic

Key Patterns

  • Simple WHERE clause: Filters rows from a single table
  • JOIN: Combines rows from two or more tables
  • GROUP BY: Aggregates data into groups
  • ORDER BY: Sorts results
  • LIMIT: Restricts the number of rows returned

Key Terminology

  • Plan Shape: The structure of the query plan tree (e.g., scan → filter → aggregate)
  • Join Type: Nested Loop, Hash Join, Merge Join
  • Aggregate: Node that performs grouping and calculations
  • Sort: Node that orders rows

4. Detailed Explanation and Examples (25-30 minutes)

Understanding Common Query Plans

Each pattern produces a typical plan. Let’s look at examples and what to expect.

Simple WHERE Clause

EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'test@example.com';
  • With an index: Index Scan
  • Without an index: Seq Scan

JOIN Patterns

EXPLAIN ANALYZE SELECT * FROM users u JOIN orders o ON u.id = o.user_id;
  • Small tables: Nested Loop
  • Large tables: Hash Join or Merge Join (if sorted)

GROUP BY Patterns

EXPLAIN ANALYZE SELECT status, COUNT(*) FROM users GROUP BY status;
  • May see HashAggregate or GroupAggregate nodes

ORDER BY Patterns

EXPLAIN ANALYZE SELECT * FROM orders ORDER BY created_at DESC;
  • With index: may avoid explicit Sort
  • Without index: Sort node appears

LIMIT Patterns

EXPLAIN ANALYZE SELECT * FROM orders ORDER BY created_at DESC LIMIT 10;
  • May use Top-N Heap or Limit node

Practical Applications

  • Use plan shapes to spot missing indexes
  • Predict when sorts or joins will be expensive
  • Tune queries for better performance

Common Misconceptions

  1. Misconception: “All joins are slow.” Reality: The right join type and indexes can make joins very fast.
  2. Misconception: “Adding LIMIT always makes queries fast.” Reality: Without proper indexes, PostgreSQL may still scan/sort the whole table.

5. Live Coding Demonstration (20-25 minutes)

Example 1: Simple WHERE Clause

EXPLAIN ANALYZE SELECT * FROM users WHERE id = 42;

Explanation:

  • With a primary key index, expect an Index Scan.
  • Without an index, expect a Seq Scan.

Example 2: Join Plan

EXPLAIN ANALYZE SELECT * FROM users u JOIN orders o ON u.id = o.user_id WHERE o.amount > 100;

Key Points:

  • Join type depends on table size and indexes.
  • Look for Hash Join, Nested Loop, or Merge Join.

Example 3: GROUP BY and ORDER BY

EXPLAIN ANALYZE SELECT status, COUNT(*) FROM users GROUP BY status ORDER BY status;

Key Points:

  • May see HashAggregate and Sort nodes.
  • Index on status can help with sorting.

Debugging Demonstration

Show how missing indexes affect plan shape:

-- No index on created_at
EXPLAIN ANALYZE SELECT * FROM orders ORDER BY created_at DESC LIMIT 10;
-- Add index
CREATE INDEX idx_orders_created_at ON orders (created_at DESC);
EXPLAIN ANALYZE SELECT * FROM orders ORDER BY created_at DESC LIMIT 10;

6. Hands-On Practice (30-40 minutes)

Exercise 1: Basic Practice (10 minutes)

Objective: Write and analyze simple WHERE and JOIN queries

Instructions:

  1. Write a SELECT with a WHERE clause on a table
  2. Write a JOIN between two tables
  3. Run EXPLAIN ANALYZE and note the plan nodes

Starter Code:

EXPLAIN ANALYZE SELECT * FROM your_table WHERE some_column = 'value';
EXPLAIN ANALYZE SELECT * FROM table1 t1 JOIN table2 t2 ON t1.id = t2.t1_id;

Solution:

-- Example output
Index Scan on your_table ...
Hash Join ...

Exercise 2: Intermediate Challenge (15 minutes)

Objective: Analyze GROUP BY, ORDER BY, and LIMIT queries

Requirements:

  • Write queries using these clauses
  • Run EXPLAIN ANALYZE and identify plan nodes
  • Add indexes and observe plan changes

Hints:

  • Try with and without indexes
  • Look for Sort, Aggregate, and Limit nodes

Exercise 3: Creative Application (15 minutes)

Objective: Explore plan shapes for more complex queries

Challenge:

  • Combine JOIN, GROUP BY, ORDER BY, and LIMIT in one query
  • Predict the plan shape, then check with EXPLAIN ANALYZE

Extension Ideas:

  • Try with subqueries or CTEs
  • Experiment with different data sizes

7. Common Pitfalls and Troubleshooting (10 minutes)

Frequent Mistakes

  1. Problem: Assuming LIMIT always makes queries fast Cause: No supporting index, so full scan/sort still happens Solution: Add appropriate indexes for ORDER BY/LIMIT

  2. Problem: Ignoring join type in plans Cause: Not checking if join is optimal for data size Solution: Review join types and add indexes as needed

Debugging Tips

  • Use EXPLAIN ANALYZE to see real execution
  • Add indexes and compare plan shapes
  • Check for unnecessary sorts or full scans

8. Best Practices and Professional Tips (5 minutes)

Industry Standards

  • Index columns used in WHERE, JOIN, ORDER BY, and GROUP BY
  • Use LIMIT with supporting indexes for pagination
  • Regularly review query plans for common patterns

Next Steps in Your Learning Journey

  • Learn to visualize complex plans (see Day 7)
  • Explore advanced query patterns and anti-patterns
  • Practice with real-world queries and data

9. Summary and Review (5 minutes)

Key Takeaways

  1. Recognize plan shapes for common query patterns
  2. Indexes and join types have a big impact on performance
  3. Use EXPLAIN ANALYZE to validate and tune queries

Quick Review Questions

  1. What plan node do you expect for a WHERE clause on an indexed column?
  2. How does PostgreSQL choose a join type?
  3. Why might a LIMIT query still be slow?

For Instructors

Teaching Tips

  • Use real queries from your application for demos
  • Show before/after plans when adding indexes
  • Emphasize the importance of plan shape recognition

Assessment Ideas

  • Have students predict plan shapes for given queries
  • Ask students to optimize a slow query and explain the plan
  • Peer review: students share and discuss their plan findings

Adaptation Notes

  • For beginners: focus on simple WHERE and JOIN queries
  • For advanced students: include multi-table joins and subqueries
  • Online: use screen sharing to walk through plan analysis