top of page

Welcome
to NumpyNinja Blogs

NumpyNinja: Blogs. Demystifying Tech,

One Blog at a Time.
Millions of views. 

Understanding Indexes in PostgreSQL

Jun 5
4 min read

 

 

When working with large datasets, even simple queries can become slow. PostgreSQL solves this problem using indexes  one of the most powerful tools for improving query performance. In this blog, we’ll explore what indexes are, why they matter, and how to use them effectively with real PostgreSQL examples. What Is an Index?

An index in PostgreSQL is a data structure (usually a B‑Tree) that helps the database find rows faster — just like an index in a book helps you find a topic without reading every page.

Without an index → PostgreSQL scans the entire table (sequential scan) With an index → PostgreSQL jumps directly to the matching rows (index scan) Why Do We Need Indexes?

Indexes improve performance when queries involve:

  • Searching (WHERE conditions)

  • Filtering

  • Sorting (ORDER BY)

  • Joining tables

  • Enforcing uniqueness

However, indexes also have a cost:

  • They take extra storage

  • They slow down INSERT, UPDATE, DELETE operations

So indexes must be used wisely.

Sample Table : Let’s create a simple table and Insert Sample date



1. Creating a Basic Index

Suppose you frequently search customers by email.

SELECT * FROM customer WHERE email = 'john@gmail.com';

If the table has millions of rows, this query becomes slow.


2. Unique Index

If you want to ensure no two customers use the same email. CREATE UNIQUE INDEX idx_customer_email_unique ON customer(email); This prevents duplicate emails and speeds up lookups.

3. Composite Index (Multiple Columns)

If your queries filter by name + age.


SELECT * FROM customer WHERE name = 'John' AND age = 25;


Create a composite index


CREATE INDEX idx_customer_name_age ON customer(name, age);

Important:

Order matters.

This index helps:

  • WHERE name = 'John' AND age = 25

  • WHERE name = 'John'

But not:

  • WHERE age = 25

4. Index for Sorting (ORDER BY)


If you frequently sort by age.

SELECT FROM customer ORDER BY age;

Create an index:

CREATE INDEX idx_customer_age ON customer(age);

This speeds up sorting operations.

5. Partial Index (Very Powerful)


If you only search for adult customers.

SELECT FROM customer WHERE age > 18;

Instead of indexing the whole table, create a partial index.

CREATE INDEX idx_customer_adults ON customer(age) WHERE age > 18;

This index is

  • Smaller

  • Faster

  • More efficient.


6. Checking Index Usage


To see if PostgreSQL is using your index.

EXPLAIN ANALYZE

SELECT * FROM customer WHERE email = 'john@gmail.com';

If the index is used, you will see the details.





7.Dropping an Index

If an index is no longer needed.


DROP INDEX idx_customer_email;


Best Practices for Indexing


  • Index columns used in WHERE, JOIN, and ORDER BY

  • Avoid indexing every column — it slows down writes

  • Use composite indexes carefully (order matters)

  • Use partial indexes for filtered queries

  • Use EXPLAIN ANALYZE to verify index usage

Avoid indexing low‑cardinality columns (ex: gender) Clustered vs Non‑Clustered Indexes in PostgreSQL When people talk about indexes, you’ll often hear the terms clustered and non‑clustered. These concepts help you understand how data is physically stored and how PostgreSQL retrieves it efficiently.

PostgreSQL does not support “clustered indexes” in the same way SQL Server or MySQL do. But PostgreSQL can physically reorder a table based on an index — using the CLUSTER command — which achieves a similar effect. What Is a Clustered Index?


A clustered index determines the physical order of rows in a table.

  • The table data is stored in the same order as the index

  • Only one clustered index can exist per table (because data can be stored in only one order)

It improves performance for range queries and sequential scans PostgreSQL does not automatically maintain clustered indexes. But you can manually cluster a table: CLUSTER customer USING idx_customer_age; This physically rewrites the table so rows are stored in the order of age. What Is a Non‑Clustered Index?


A non‑clustered index is the standard index type in PostgreSQL.

  • It stores index entries separately from the table

  • Each index entry points to the actual row (via TID — tuple identifier)

  • You can create multiple non‑clustered indexes on a table

  • These are the indexes you create with CREATE INDEX CREATE INDEX idx_customer_email ON customer(email); Key Differences (Simple & Clear)


Feature

Clustered Index

Non- Clustered Index

Physical order of table

Matches index

Unrelated to index

Number allowed

Only one

Many

Storage

Table itself is the index

Separate index structure

Best for

Range queries, sequential scans

Lookups, filtering, joins

PostgreSQL support

Manual via CLUSTER

Fully supported

When Should You Use CLUSTER in PostgreSQL?


Use clustering when:

  • You frequently run range queries   SELECT * FROM customer WHERE age BETWEEN 20 AND 40; The table is mostly read‑heavy

  • The column has good ordering (e.g., timestamps, numeric ranges)

  • Avoid clustering when:

  • The table is write‑heavy

  • Data changes frequently

  • You need real‑time ordering (PostgreSQL does not maintain clustering automatically)

Conclusion

Indexes are one of the most powerful tools for improving PostgreSQL performance. By understanding how and when to use different types of indexes — basic, unique, composite, partial, and even manually‑clustered indexes — you can dramatically speed up data retrieval and make your applications more efficient and scalable.

PostgreSQL uses non‑clustered indexes by default, which help with fast lookups, filtering, joins, and sorting. When you need to optimize range‑based queries or improve sequential scan performance, you can simulate a clustered index using the CLUSTER command to physically reorder the table. However, because PostgreSQL does not maintain clustering automatically, this technique should be used selectively on read‑heavy tables.

 
 

+1 (302) 200-8320

NumPy_Ninja_Logo (1).png

Numpy Ninja Inc. 8 The Grn Ste A Dover, DE 19901

© Copyright 2025 by Numpy Ninja Inc.

  • Twitter
  • LinkedIn
bottom of page