Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
title: "Improving Query Performance with Indexes using Prisma: Introduction"
slug: "improving-query-performance-using-indexes-1-zuLNZwBkuL"
date: "2022-09-06"
updatedAt: "2026-07-08"
authors:
- "Alex Ruheni"
metaTitle: "Improving query performance with database indexes using Prisma: Introduction"
metaDescription: "Learn the fundamentals of database indexes: what they are, the problem they solve, and their benefit and cost"
metaTitle: "Database Indexes Explained: What They Are and When to Use Them"
metaDescription: "A database index is a secondary data structure that speeds up reads by reducing search scope. Learn the main index types, what they cost, and when to add one."
metaImagePath: "/improving-query-performance-using-indexes-1-zuLNZwBkuL/imgs/meta-c92a4afeb9d9b1df6f8104fced300d5e49233bd0-1269x714.png"
heroImagePath: "/improving-query-performance-using-indexes-1-zuLNZwBkuL/imgs/hero-1c62649f62f41f22d8a54c882cd24da906c51479-844x474.svg"
heroImageAlt: "Improving Query Performance with Indexes using Prisma: Introduction"
Expand All @@ -15,34 +16,21 @@ tags:
- "education"
---

One strategy for improving the performance of your database queries is using _indexes_. This article covers the fundamentals of database indexes: what they are, how they work, and their cost and benefits.

## Overview
- [What we can learn about databases from a book library](#what-we-can-learn-about-databases-from-a-book-library)
- [Storing books in smaller shelves (partitioning)](#storing-books-in-smaller-shelves-partitioning)
- [More people searching leads to faster searches (query parallelization)](#more-people-searching-leads-to-faster-searches-query-parallelization)
- [Using a catalog to store book metadata for faster retrieval (indexes)](#using-a-catalog-to-store-book-metadata-for-faster-retrieval-indexes)
- [Conclusion: You can speed up search time by reducing search scope](#conclusion-you-can-speed-up-search-time-by-reducing-search-scope)
- [What are database indexes?](#what-are-database-indexes)
- [Types of database indexes](#types-of-database-indexes)
- [Anatomy of a database query](#anatomy-of-a-database-query)
- [Sequential scans go through the entire table](#sequential-scans-go-through-the-entire-table)
- [Index scans first look up metadata to find the record faster](#index-scans-first-look-up-metadata-to-find-the-record-faster)
- [Index-only scans look up the record in the index directly](#index-only-scans-look-up-the-record-in-the-index-directly)
- [The price you pay for faster reads](#the-price-you-pay-for-faster-reads)
- [Summary and next steps](#summary-and-next-steps)
A database index is a smaller, secondary data structure the database uses to find matching rows without scanning the whole table. Indexes are the most common way to speed up slow read queries, and they come with a cost on writes and storage. This article covers the fundamentals: what indexes are, how the database decides to use them, the main index types, and when adding one is worth it. Parts [two](/improving-query-performance-using-indexes-2-MyoiJNMFTsfq) and [three](/improving-query-performance-using-indexes-3-kduk351qv1) of this series put the theory into practice with B-tree and hash indexes in a [Prisma ORM](https://www.prisma.io/orm) schema.

> **Updated (July 2026):** Revised as part of a refresh of this series. The fundamentals in this introduction are version independent; the hands-on measurements in [part two](/improving-query-performance-using-indexes-2-MyoiJNMFTsfq) were verified end-to-end on Prisma ORM 7.8 and PostgreSQL 17.

## What we can learn about databases from a book library

A database is like a library. Books in a library are usually well organized, much like data in a database. Both provide great structures for storing vast amounts of information for later retrieval.
A database is like a library. Books in a library are usually well organized, much like data in a database. Both provide great structures for storing vast amounts of information for later retrieval.

Continuing with the library analogy, libraries store large amounts of data. The more books you have, the longer the time it takes to find a book. The time taken to retrieve a book can be influenced by the strategy for **storing** and **searching** books in the library.
Continuing with the library analogy, libraries store large amounts of data. The more books you have, the longer the time it takes to find a book. The time taken to retrieve a book can be influenced by the strategy for **storing** and **searching** books in the library.

### Storing books in smaller shelves (partitioning)

You may naively organize the books into one big shelf alphabetically according to the title, for example. One strategy for retrieving a book faster would be storing them in smaller bookshelves in alphabetical ranges.

This is similar to [_partitioning_](https://docs.gitlab.com/ee/development/database/table_partitioning.html) a table in a database. A table is split into smaller chunks by a _partition key_ which is included in a query. A partition key is the column used to split the table. The database narrows down the data to be queried using the partition key.
This is similar to [_partitioning_](https://www.postgresql.org/docs/current/ddl-partitioning.html) a table in a database. A table is split into smaller chunks by a _partition key_ which is included in a query. A partition key is the column used to split the table. The database narrows down the data to be queried using the partition key.

![Table Partitioning](/improving-query-performance-using-indexes-1-zuLNZwBkuL/imgs/table-partitioning.png)

Expand All @@ -68,9 +56,9 @@ The rest of the article will explore database indexes: what they are and how the

A database index is a smaller, secondary data structure used by the database server to store a subset of a table's data. Indexes are commonly used to improve the read performance of a given table.

Indexes contain key-value pairs:
Indexes contain key-value pairs:
- **key**: the column(s) that will be used to create an index
- **value**: and a pointer to the record in the specific table
- **value**: and a pointer to the record in the specific table
Comment on lines +59 to +61

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix grammatical error in the "value" bullet.

The bullet starts with "and," which doesn't read correctly in a list context. It should describe the value directly.

✏️ Proposed fix
 - **value**: and a pointer to the record in the specific table
+- **value**: a pointer to the record in the specific table
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Indexes contain key-value pairs:
- **key**: the column(s) that will be used to create an index
- **value**: and a pointer to the record in the specific table
- **value**: and a pointer to the record in the specific table
Indexes contain key-value pairs:
- **key**: the column(s) that will be used to create an index
- **value**: a pointer to the record in the specific table
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/blog/content/blog/improving-query-performance-using-indexes-1-zuLNZwBkuL/index.mdx`
around lines 59 - 61, The “value” bullet in the indexes description has a
grammar issue because it starts with “and” in a list item. Update the bullet in
the Indexes section of the blog content so the description of the value stands
on its own, using the existing “Indexes contain key-value pairs” list near the
key/value bullets.


You can index more than one column in a table. For example, if you have a table called `User` with 3 columns:`id`, `firstName`, and `lastName`, you can create one index on the `firstName` and `lastName` columns.

Expand All @@ -83,25 +71,25 @@ There are different types of indexes, each one suitable for a different use case
- **Index (default)**: a normal, non-unique index that does not enforce any constraints on your data
- **Primary keys**: used to uniquely identify a row in a table
- **Unique indexes**: used to enforce uniqueness of a value in a column, preventing duplicate values
- **Full-text indexes**: used on text columns and enables [full-text search](https://www.joshgraham.com/full-text-search-explained/)
- **Full-text indexes**: used on text columns and enables [full-text search](https://www.postgresql.org/docs/current/textsearch-intro.html)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix subject-verb agreement for "Full-text indexes".

"Full-text indexes" is plural, so "enables" should be "enable".

✏️ Proposed fix
 - **Full-text indexes**: used on text columns and enables [full-text search](https://www.postgresql.org/docs/current/textsearch-intro.html)
+- **Full-text indexes**: used on text columns and enable [full-text search](https://www.postgresql.org/docs/current/textsearch-intro.html)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- **Full-text indexes**: used on text columns and enables [full-text search](https://www.postgresql.org/docs/current/textsearch-intro.html)
**Full-text indexes**: used on text columns and enable [full-text search](https://www.postgresql.org/docs/current/textsearch-intro.html)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/blog/content/blog/improving-query-performance-using-indexes-1-zuLNZwBkuL/index.mdx`
at line 74, Fix the subject-verb agreement in the “Full-text indexes” bullet by
changing the verb in the markdown content to match the plural subject; update
the text in the blog post snippet so “Full-text indexes” uses “enable” instead
of “enables.”


There are more specialized types of indexes different databases support. Some of the other types include hash indexes, GIN indexes for PostgreSQL, and clustered indexes for SQL server.
There are more specialized types of indexes different databases support. Some of the other types include hash indexes, GIN indexes for PostgreSQL, and clustered indexes for SQL Server.

> The tutorial series will cover more specialized indexes that Prisma supports in future articles. Stay tuned!
> This series covers the two most common index types in practice: [B-tree indexes in part two](/improving-query-performance-using-indexes-2-MyoiJNMFTsfq) and [hash indexes in part three](/improving-query-performance-using-indexes-3-kduk351qv1), both defined directly in a Prisma schema.

### Anatomy of a database query

When the database receives a query, it first creates a _query plan_. A query plan is a list of instructions the database needs to follow to execute a given query.
When the database receives a query, it first creates a _query plan_. A query plan is a list of instructions the database needs to follow to execute a given query.

The query plan specifies how the database intends to retrieve records. The database chooses the most optimal query strategy.

You can prefix your SQL query with `EXPLAIN` to see information about your database's query plan. [Josh Berkus](https://twitter.com/fuzzychef) gave a presentation on "Explaining EXPLAIN" if you are interested in learning more about the PostgreSQL query planner.
You can prefix your SQL query with `EXPLAIN` to see information about your database's query plan. Josh Berkus, a former PostgreSQL core team member, explains the query planner in "Explaining EXPLAIN", a talk from a Prisma online meetup:

<Youtube videoId="ZOZglRUjfFI" />

### Sequential scans go through the entire table

One path the database might choose is look through each row in a table to find the records matching the filters. This is known as a _sequential scan_ or _full table scan_.
One path the database might choose is look through each row in a table to find the records matching the filters. This is known as a _sequential scan_ or _full table scan_.

If you're working with a large dataset, sequential scans will slow down your queries. The time taken to find a record is influenced by the size of your dataset. The bigger the dataset, the longer it takes to retrieve a record.

Expand All @@ -114,9 +102,9 @@ Another path the database might choose is query the index, matching the filter w
The database might also choose to return the matching records from the index without even "consulting" the original table. This is known as an _index-only scan_. This can happen when the columns being returned and being filtered on already exist in the index. Here's an example that could make use of an index-only scan.

```sql
SELECT firstName from 'User' where firstName = 'Jimmy';
SELECT "firstName" FROM "User" WHERE "firstName" = 'Jimmy';
```
Other database providers such as PostgreSQL support other types of query plans such as [bitmap heap scan](https://pganalyze.com/docs/explain/scan-nodes/bitmap-heap-scan) and [bitmap index scans](https://pganalyze.com/docs/explain/scan-nodes/bitmap-index-scan) will not be covered in this series.
Other database providers such as PostgreSQL support other types of query plans such as [bitmap heap scan](https://pganalyze.com/docs/explain/scan-nodes/bitmap-heap-scan) and [bitmap index scans](https://pganalyze.com/docs/explain/scan-nodes/bitmap-index-scan). You will see a bitmap index scan in action in [part two](/improving-query-performance-using-indexes-2-MyoiJNMFTsfq) of this series.

### The price you pay for faster reads

Expand All @@ -128,9 +116,25 @@ The other cost of indexes is that they require additional resources from the dat

**A general rule of thumb is to use indexes sparingly and on columns that are queried frequently.** You should also select the appropriate index type based on your requirements.

## Frequently asked questions

<Accordions type="single">
<Accordion title="What is a database index?">
A database index is a smaller, secondary data structure that stores a subset of a table's data as key-value pairs: the indexed column values as keys, and pointers to the full rows as values. The database uses it to find matching rows without scanning the entire table, which turns slow full-table reads into fast lookups.
</Accordion>
<Accordion title="What is the difference between a sequential scan and an index scan?">
In a sequential scan the database reads every row in the table and filters out the ones that match, so the cost grows linearly with table size. In an index scan the database first looks up matching entries in the index and then fetches only those rows from the table. Run `EXPLAIN` on a query to see which plan the database chose.
</Accordion>
<Accordion title="Why not index every column?">
Every index must be updated on every insert, update, or delete that touches its column, so each one adds write overhead, storage, and maintenance cost. Index the columns your queries filter and sort on frequently, and skip the rest.
</Accordion>
<Accordion title="What types of database indexes are there?">
The common categories are the default non-unique index, primary keys, unique indexes, and full-text indexes. Databases also offer specialized types such as B-tree indexes (the default in PostgreSQL, good for equality and range queries), hash indexes (equality only), and GIN indexes for values like JSON and arrays.
</Accordion>
</Accordions>

## Summary and next steps

In this article, you learned what a database index is, the different types of database indexes, the anatomy of a database query, and the cost of using database indexes to optimize your queries.

In the next article, you will learn how you can improve the performance of your existing query using indexes in your application with Prisma.

In [part two](/improving-query-performance-using-indexes-2-MyoiJNMFTsfq), you will put this into practice: declare a B-tree index with `@@index` in a Prisma schema, measure a query over 500,000 rows before and after with `EXPLAIN ANALYZE`, and watch it get about 80x faster. Because the index lives in your Prisma schema, it is declared in code, reviewed with the rest of your changes, and applied the same way in every environment, from a local [Prisma Postgres](https://www.prisma.io/docs/postgres) database to production. [Part three](/improving-query-performance-using-indexes-3-kduk351qv1) does the same for hash indexes.
Loading