Indroduction
Ruby and Rails apps often slow down as they grow in scale. While the Ruby language or Rails framework isn’t always the direct cause, inefficient Active Record queries frequently are. This post shows you how to detect and fix query bloat to keep your app fast and responsive.
Problem
As Rails applications grow, developers often notice performance slowdowns—especially on pages that query complex data. One of the most common causes is Active Record query bloat:
- Unintended full-table scans
- Unused
.includes
or.joins
- Poorly indexed columns
- Complex
WHERE
conditions or largeOR
queries - Unoptimized scopes or chaining
This often goes undetected until it impacts user experience or server performance.
Solution
Teach developers how to analyze and optimize Active Record queries using built-in Rails tools and external gems, improving speed and scalability.
What Is Query Bloat in Ruby and Rails?
Active Record query bloat happens when the ORM generates more or slower queries than necessary. This often creeps in silently as your app grows.
Example of Bloat:
ruby
User.where("name LIKE ?", "%john%").includes(:posts).order("created_at desc")
How to Detect Query Bloat in Ruby and Rails
- Use
ActiveRecord::Base.logger = Logger.new(STDOUT)
in development - Use Bullet gem to detect unnecessary queries
- Explain EXPLAIN ANALYZE for PostgreSQL query insight
Common Ruby and Rails Query Mistakes and How to Fix Them
❌Overusing .includes
without needing associations
✅ Only eager load when necessary
❌ Querying large datasets in view
✅ Use pagination with kaminari
or pagy
❌ String-based SQL conditions
✅ Use ARel or hash-based conditions for safety and optimization
Optimizing Indexes and Scopes in Ruby and Rails Apps
As your Rails app grows and your database expands, unindexed queries and inefficient scopes can significantly degrade performance. Here’s how to fix that.
1. Adding Indexes in Ruby and Rails Apps
Database indexes allow queries to search large tables much faster. Without them, your app might scan entire tables (called a full table scan)—which is slow and costly.
How to Add Indexes in Rails:
Use a migration to create indexes on frequently queried columns:
bash
rails generate migration AddIndexToUsersEmail
ruby
# db/migrate/xxxx_add_index_to_users_email.rb
add_index :users, :email
Then run:
bash
rails db:migrate
Example: Querying by Timestamps
If you use a condition like:
ruby
User.where("created_at > ?", 1.week.ago)
You should ensure created_at
is indexed. Otherwise, the database will scan every row to evaluate the condition. Add this index:
ruby
add_index :users, :created_at
2. How to Use select()
in Ruby and Rails for Faster Queries
By default, Active Record queries fetch all columns using SELECT *
. But in many cases, you only need specific columns, especially in background jobs or API responses.
Use select()
to Limit Overhead:
ruby
User.select(:id, :email).where(active: true)
This reduces memory usage and network overhead between your app and database.
Ruby and Rails Case Study: Cutting Page Load Time
Before | After |
17 queries, 1.2s load time | 5 queries, 240ms load time |
select()
and paginationConclusion: Making Ruby and Rails Apps Faster
Your Rails app doesn’t have to slow down with scale. Most of the performance pain points come from inefficient queries—not Ruby or Rails itself.
Want more Rails optimization guides? Visit SaasTrail for practical tips and advanced patterns.