Understanding Indexes: A Guide to Database Optimization
Learn how indexing works to boost query performance. From understanding B-trees to creating your first index, master the basics of database optimization today.

Previously in this course, we covered CRUD operations and schema testing for SaaS databases. While those operations allow us to interact with data, as your SaaS application grows, simply having a correct schema isn't enough; you need to ensure that data retrieval remains fast even with millions of rows. This lesson introduces indexing, the primary mechanism for database optimization.
How Indexes Work: The "Index Card" Analogy
Imagine a massive library with millions of books. If you want to find a book by its title, you could walk through every single aisle and check every book—this is what a database calls a "Full Table Scan." It is slow, resource-intensive, and unsustainable.
An index is essentially the library’s card catalog. It contains a small, sorted list of titles alongside a pointer (the "call number") that tells you exactly where the book lives on the shelf. In database terms, an index is a separate data structure stored on disk that allows the database engine to find specific rows without reading the entire table.
The Power of B-trees
Most relational databases (like PostgreSQL or MySQL) use a B-tree (Balanced Tree) structure for their default indexes. A B-tree is a self-balancing search tree that keeps data sorted and allows for search, sequential access, and insertions in logarithmic time.
When you perform a query like SELECT * FROM users WHERE email = 'user@example.com', the database engine traverses the B-tree from the root node down to the leaf node where the email address is stored. Because the tree is balanced, the number of steps required to find your data is tiny, even if your users table contains millions of records. For a deeper look at different structures, see how B-Tree Index vs Hash Index: Choosing the Right SQL Indexing impacts your specific use cases.
Identifying Columns for Indexing
You shouldn't index every column. Every time you add an index, the database must update that index whenever you INSERT, UPDATE, or DELETE a row. This creates "write overhead." To decide which columns to index, follow these rules:
- High-Cardinality Columns: Columns with many unique values (e.g.,
email,username,phone_number) are perfect candidates. - Filter Clauses: Any column frequently appearing in a
WHEREclause is a prime candidate. - Join Keys: Foreign keys used in
JOINstatements should almost always be indexed to keep relational performance snappy.
Creating Basic Indexes
Creating an index is straightforward using the CREATE INDEX SQL command. In our SaaS project, we frequently look up users by their email address during the login process. Let’s add an index to the users table to speed this up.
SQL-- Syntax: CREATE INDEX index_name ON table_name (column_name); CREATE INDEX idx_users_email ON users (email);
Once this command runs, the database engine creates the B-tree structure. From now on, any query filtering by email will automatically use this index instead of scanning the full table.
Hands-on Exercise
Reflect on your current SaaS project schema. Look at your subscriptions table. You likely have a user_id column acting as a foreign key that connects a subscription to a specific user.
- Identify the column in your
subscriptionstable that is most frequently used to filter data (e.g.,user_idorstatus). - Write the
CREATE INDEXstatement to index that column. - Constraint Check: Remember that Primary Keys are indexed automatically by the database. Did you already have an index on your PK? (Yes, you did!)
Common Pitfalls
- Over-indexing: Adding indexes to every column will slow down your
INSERTandUPDATEstatements significantly. Only add indexes that you have a business case for (i.e., you have a query that is slow). - Indexing Low-Cardinality Columns: Indexing a column like
genderoris_active(boolean) is rarely effective because the database engine might decide a full scan is faster anyway. - Ignoring Index Maintenance: As your data changes, indexes can become fragmented. While modern databases handle this well, it is a concept you will need to monitor as your application scales.
FAQ
Q: If I create an index, do I need to change my SELECT queries?
A: No. The database engine's query optimizer is smart enough to detect the existence of an index and use it automatically if it determines it will speed up the request.
Q: Can I index multiple columns? A: Yes, these are called Composite Indexes. We will cover those in a future lesson, as the order of columns in a composite index is critical.
Q: Does an index change the data in my table? A: No. An index is a "sidecar" structure. It holds a sorted copy of the data (or a reference to it) but doesn't change the underlying table or your application logic.
Recap
Indexing is your primary tool for database optimization. By creating sorted B-tree structures for your high-cardinality and filter-heavy columns, you dramatically reduce the time it takes to retrieve data. Start by indexing your most queried columns, but be mindful of the trade-offs regarding write performance. For more advanced strategies, you might eventually explore PostgreSQL Indexing: B-Tree vs GIN for Better Query Performance or learn how to use Postgres Partial Indexes: Optimizing High-Traffic Query Performance to save space.
Up next: Primary Key Indexing — we will look deeper at how your Primary Key acts as the foundation for the table's data organization.
Work with me

Laravel Bug Fixes, Maintenance & Optimization
Stuck on a Laravel bug or a slow app? Fast, reliable fixes, upgrades, and performance tuning from an experienced Laravel engineer.

FilamentPHP Admin Panel & Dashboard Development
A powerful admin panel for your Laravel app — built with FilamentPHP so you can manage everything without touching the database.


