Back to Blog
Lesson 44 of the PostgreSQL: SQL & PostgreSQL from Scratch course
DatabasesSeptember 2, 20264 min read

Analyzing Query Plans: How to Optimize PostgreSQL Performance

Master the EXPLAIN command to reveal how PostgreSQL executes your queries. Learn to read execution plans, spot bottlenecks, and optimize for speed.

PostgreSQLSQLDatabase PerformanceQuery OptimizationEXPLAIN
A close-up of a hand with a pen analyzing data on colorful bar and line charts on paper.

Previously in this course, we covered database security basics to control user access. Now, we shift our focus to performance: understanding exactly how PostgreSQL processes your commands so you can diagnose and fix slow queries.

When you send a SQL statement to PostgreSQL, the database doesn't just "run" it. It acts as a strategist, evaluating dozens of possible ways to retrieve your data—using indexes, scanning tables, or joining datasets—and choosing the one it estimates will be fastest. The EXPLAIN command is your window into that strategy.

Visualizing Execution with EXPLAIN

The EXPLAIN command displays the execution plan for a query without actually running it. This is your primary tool for auditing schema performance and identifying why a query might be dragging down your application.

To use it, simply prefix your query with the keyword EXPLAIN. Let's look at a hypothetical query from our store application where we search for a customer by their email:

SQL
EXPLAIN SELECT * FROM customers WHERE email = 'jane.doe@example.com';

When you run this, PostgreSQL returns a tree-like output. Here is a typical example of what you might see:

TEXT
Index Scan using customers_email_key on customers  (cost=0.15..8.17 rows=1 width=120)
  Index Cond: (email = 'jane.doe@example.com'::text)

How to Read an Execution Plan

To understand the output, you need to recognize the "verbs" of the database. The most common operations you will encounter include:

  • Seq Scan (Sequential Scan): The database reads the entire table from start to finish. If your customers table has 10,000 rows, it reads 10,000 rows. This is often a bottleneck on large tables.
  • Index Scan: The database uses a B-tree index (which we discussed in our previous look at indexes) to jump directly to the target data. This is significantly faster.
  • Hash Join / Nested Loop: These describe how the database combines two tables. If you are comparing SQL join optimization strategies, you'll see these frequently when joining orders to customers.

Identifying Bottlenecks

Look for high cost values and large rows estimates. If you see a Seq Scan on a table with a large number of rows, it is an immediate signal that you are missing an index. If you are analyzing resource bottlenecks, look for operations where the "actual time" (available if you use EXPLAIN ANALYZE) is significantly higher than the estimated cost.

Hands-on Exercise: Diagnosing a Scan

  1. Open your terminal or psql interface.
  2. Run an EXPLAIN on a query that selects all items from your products table where the price is greater than 50.
  3. Note whether it performs a Seq Scan or an Index Scan.
  4. If it is a Seq Scan, imagine the impact on a store with 1 million products versus 10 products.

Common Pitfalls

  • Forgetting ANALYZE: Plain EXPLAIN only shows the estimate. If you want to see the actual time it took to run, use EXPLAIN (ANALYZE, BUFFERS). This executes the query and provides real-world performance metrics.
  • Ignoring Table Size: A Seq Scan on a table with 5 rows is perfectly fine. Don't waste time "optimizing" queries on tiny development tables; focus your efforts on tables that will grow large.
  • Misinterpreting Costs: The numbers in the parentheses (e.g., cost=0.15..8.17) are arbitrary units of work, not seconds or milliseconds. They are only useful for comparing one plan against another.

FAQ

Q: Does EXPLAIN execute my query? A: No, EXPLAIN only shows the plan. EXPLAIN ANALYZE executes the query and shows the plan along with the actual execution time.

Q: Why does my query use a Seq Scan even though I have an index? A: PostgreSQL may decide an index is not useful if the query retrieves a large percentage of the table (e.g., selecting 80% of all rows). It is often faster to scan the whole table than to jump back and forth to the index.

Q: How do I read the output hierarchy? A: Read it from the inside out (or bottom to top). The innermost (bottom) operations are performed first, and their results are passed up to the parent operations.

Recap

EXPLAIN is your primary tool for understanding query execution. By identifying inefficient operations like Seq Scans where indexes should be used, you can resolve performance issues before they impact your users. Remember that an execution plan is a guide to how PostgreSQL processes your data, and learning to read it is the hallmark of a skilled database practitioner.

Up next: We will explore how to use schema namespaces to organize your store data as it grows in complexity.

Similar Posts