Skip to Content
Course content

137: Database Indexing for Rails Apps

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Imagine you're holding a 1,000-page technical manual on jet engines. You need to find the specific section on "Fuel Injector Calibration." You have two choices: you can start at page one and read every single sentence until you hit that phrase, or you can flip to the index at the back, find "Fuel Injector," see that it's on page 412, and jump straight there.

In database terms, reading every page is called a Full Table Scan. It's fine when your table has ten rows, but when you have ten million, your app will essentially freeze while the database grinds through every single record. The index at the back of the book is exactly what a database index is—a separate, sorted data structure that tells the database exactly where the row lives on the disk so it can skip the line.

Teaching Rails to Shortcut the Search

Most of the time, you'll be indexing columns that you use frequently in where clauses. Let's say you have a User model and you're looking up users by their email address during login. Without an index, Postgres or MySQL has to check every single user record to find the match.

You handle this in Rails via a migration. I've seen a lot of developers forget this step, only to realize their app is crawling in production. Here is how you'd add a standard index to the email column:

class AddIndexToUsersEmail 

Notice I added unique: true. This is a pro move. Not only does it speed up the search, but it creates a database-level constraint that prevents two users from ever having the same email, even if your Rails validations somehow fail during a race condition.

Handling Multiple Columns Together

Sometimes, you aren't searching by just one thing. Imagine you're building a dashboard that shows Orders filtered by both user_id and status. If you have separate indexes on both, the database has to pick one, filter the results, and then manually sift through those for the second criteria.

A composite index allows the database to look for the combination of both values simultaneously. Order matters here—the database can use the index for the first column alone, or the first and second together, but it can't use it for the second column alone.

class AddCompositeIndexToOrders 

I usually suggest putting the column with the highest "cardinality" (the one with the most unique values, like user_id) first in the array.

The Hidden Cost of Over-Indexing

It's tempting to just index every single column "just in case." Don't do that. Every time you INSERT or UPDATE a record, the database has to update the index as well. If you have ten indexes on one table, a single write operation suddenly becomes eleven write operations. You're trading write speed for read speed.

My rule of thumb? Index your foreign keys (Rails doesn't always do this automatically depending on how you write your references) and any column that appears in a where or order clause in your most-hit controllers. If you're unsure, use a tool like rack-mini-profiler or check your logs for "Slow Queries."




📋 Practical Task

Optimizing the Order History Search

You are working on a legacy Rails app where the Order table has grown to 500,000 rows. The "My Orders" page is taking 3 seconds to load because it executes this query: Order.where(user_id: current_user.id, status: 'shipped').order(created_at: :desc).

Currently, there is an index on user_id, but the database is still struggling to filter by status and sort by date.

Your Task: Generate and write a migration that adds a composite index to the orders table. This index should optimize the query by covering the user_id, the status, and the created_at timestamp in a single index. Ensure the columns are ordered logically to support the filtering and the sorting.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.