🚧 Under construction — VoTechWorks is being built. A free tech program — complimentary, as our commitment to get America working.
voTechWorksGrade 13 · a vocational technology learning center, by urbanicity
newSchoolWorks.com › VoTechWorks › Technology & Design › Web & Software Development › SQL and PostgreSQL Database Development › Lesson 8
TEC-WEB46-04 · Lesson 8 · 13 clock hours · theory

Indexes, EXPLAIN, and Query Performance

Objective. Students will create B-tree indexes, interpret EXPLAIN ANALYZE output, and identify at least two query patterns that benefit from indexing on a provided dataset.

⚠ Pending professional review

This lesson, its worked examples and its practice questions has not yet been verified by an industry-certified professional or by a certification or approval body. It is a study draft and may contain errors. Do not use it as instructions for work on a job site or on live equipment. Always follow your instructor, your supervising professional, and current official references and regulations.

VoTechWorks program approval and accreditation are still in progress. Credentials are issued only by the certifying bodies named in each program, after their own exams.

Why Query Performance Matters

As databases grow, poorly written queries can turn a fraction-of-a-second response into a multi-second delay. A 50,000-row table may seem small, but production systems routinely store millions of rows. Developing good habits now—reading query plans, creating targeted indexes, and knowing when not to index—will carry through your entire career as a developer or database administrator.

How PostgreSQL Executes a Query

When you submit a SELECT statement, PostgreSQL does not run it immediately. First, the query planner examines available statistics about the table (row counts, column value distributions) and generates a query plan: a tree of steps describing exactly how data will be retrieved and joined. The planner chooses the plan it estimates will cost the least work. Understanding that plan is the first step toward improving it.

Sequential Scans vs. Index Scans

A sequential scan (Seq Scan) reads every row in a table from beginning to end—like reading a book cover to cover to find one sentence. For small tables or queries that return most rows, this is fine. For large tables where only a few rows match, it is wasteful.

An index scan uses a pre-built data structure to jump directly to matching rows—like using a book's index to find the exact page. PostgreSQL supports several index types; the default and most broadly useful is the B-tree index, which handles equality checks (`=`), range queries (`<`, `>`, `BETWEEN`), and `ORDER BY` efficiently.

Creating a B-tree Index

The syntax is straightforward:

```sql

CREATE INDEX idx_orders_customer_id

ON orders (customer_id);

```

PostgreSQL will build the index immediately and maintain it automatically as rows are inserted, updated, or deleted. Name indexes descriptively so you can identify them later (`idx_tablename_columnname` is a common convention).

Reading EXPLAIN ANALYZE Output

`EXPLAIN` shows the planner's estimated plan without running the query. `EXPLAIN ANALYZE` actually executes the query and adds real timing and row-count data. Use `EXPLAIN ANALYZE` during development; avoid it on destructive statements in production unless you wrap them in a transaction you roll back.

A typical output node looks like this:

```

Seq Scan on orders (cost=0.00..1540.00 rows=50000 width=72)

(actual time=0.032..18.451 rows=50000 loops=1)

```

Key fields to annotate:

After adding an index, a node may change from `Seq Scan` to `Index Scan` or `Bitmap Index Scan`, and the total cost and actual time should drop noticeably.

Identifying Bottleneck Columns

Look for these patterns in a query plan:

1. Seq Scan on a large table with a low `rows` estimate — the planner wants few rows but has no index to use.

2. High actual time on a single node — that node is doing most of the work.

3. Filter lines inside a Seq Scan — rows are being discarded after a full read, meaning the WHERE clause column has no index.

Columns that frequently appear in `WHERE`, `JOIN ON`, and `ORDER BY` clauses are prime index candidates.

When NOT to Index

Indexes are not free. Each index must be updated every time a row is inserted, updated, or deleted, adding overhead to write operations. Guidelines from PostgreSQL documentation and industry practice:

Recording Results: The Performance Log

A structured log makes your work reproducible and defensible. For each index you create, record: the index name, the query tested, the before cost (from EXPLAIN ANALYZE total), the after cost, and a written interpretation explaining why cost changed. This habit mirrors professional database tuning documentation.

Safety and Best Practices

PostgreSQL itself does not involve physical safety hazards, but responsible database work has its own critical rules:

Key terms8

Query plannerThe component of PostgreSQL that analyzes a SQL statement and selects the execution strategy it estimates will cost the least work.
Sequential scan (Seq Scan)An execution strategy that reads every row in a table from start to finish, regardless of how many rows match the query's conditions.
B-tree indexThe default PostgreSQL index type, organized as a balanced tree structure that supports equality, range, and sort operations efficiently.
EXPLAIN ANALYZEA PostgreSQL command that both shows the query plan and actually executes the query, returning estimated costs alongside real execution times and row counts.
Cost estimateA unitless number the planner assigns to each plan node representing relative work; reported as startup cost and total cost in EXPLAIN output.
CardinalityThe number of distinct values in a column; high-cardinality columns (many unique values) benefit most from indexing, while low-cardinality columns benefit least.
Index scanAn execution strategy that uses an index to locate matching rows directly, avoiding a full table read and typically much faster than a sequential scan for selective queries.
ANALYZEA PostgreSQL command that collects statistics about column value distributions and row counts, helping the planner make accurate cost estimates.
In class: Run EXPLAIN ANALYZE on five slow queries against a 50,000-row dataset (instructor-provided); read and annotate the query plan output, identifying sequential scans, index scans, cost estimates, and actual row counts. · Add B-tree indexes to columns identified as bottlenecks; re-run EXPLAIN ANALYZE and record before/after planning and execution times in a performance log table (index name, query, before cost, after cost, observation). · Research and present a three-minute verbal explanation of when NOT to index (low-cardinality columns, write-heavy tables, small tables) using the PostgreSQL documentation and one external reference; classmates ask two follow-up questions each.
Materials: 50,000-row performance dataset seed script (instructor-provided), PostgreSQL EXPLAIN documentation, psql, pgAdmin Query Tool, performance log template
Check: Students submit a completed performance log with at least five entries showing measurable cost reduction; pass = log contains accurate before/after data and a correct written interpretation for each index created.

Practice check8

Answer each question, then check it. Nothing is recorded; this is your own practice.

Database concepts / query optimization
1. A query plan shows 'Seq Scan on customers (cost=0.00..2200.00 rows=80000 width=50)'. What does the value 2200.00 represent?
Database development / SQL syntax
2. Which SQL statement creates a B-tree index named idx_sales_date on the sale_date column of the sales table?
Database concepts / indexing strategy
3. After adding an index to the order_status column, EXPLAIN ANALYZE still shows a sequential scan. Order_status contains only the values 'open', 'closed', and 'pending'. What is the most likely reason?
Database safety / professional practice
4. A developer runs EXPLAIN ANALYZE on a DELETE statement in a production database without a transaction wrapper. What is the risk?
Database development / indexing strategy
5. Which scenario is the BEST candidate for adding a B-tree index?
Database administration / query optimization
6. In EXPLAIN ANALYZE output, you notice the estimated rows=50 but actual rows=4800 for a node. What should you do first?
Database administration / professional practice
7. What is the primary advantage of using CREATE INDEX CONCURRENTLY instead of CREATE INDEX on a production table?
Database development / professional practice
8. Which of the following best describes the purpose of a performance log when tuning database queries?
Record this lesson on my transcript. Sign in with your key and enrollment email to record lessons (enroll free if you have no key). This page stays open to read and practise.