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 large OR 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

BeforeAfter
17 queries, 1.2s load time5 queries, 240ms load time
What changed: indexed foreign keys, removed N+1, used select() and pagination

Conclusion: 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.