0%
Reading Settings
Font Size
18px
Line Height
1.5
Letter Spacing
0.01em
Font Family
Table of contents

Reducing ActiveRecord Queries to Speed Up Your Requests
Software Engineer
Software Engineer
Ruby on Rails
Ruby on Rails

In Rails, ActiveRecord is one of the things that makes the framework so enjoyable to use. It reads almost like natural language and lets you write database logic in a clean, Ruby-style way.
But every line of Active Record still turns into real SQL behind the scenes. Every SQL query comes with a fixed cost:
- Network latency between your app and the database (even on localhost)
- Query parsing and planning time inside PostgreSQL
- Serialization of results back to Ruby
- Context switching inside your Rails process
For simple requests, the delay might only be a few milliseconds. But in production, when a single request fires dozens of queries, that overhead can quickly add up to 100–200 ms. Reducing the number of SQL queries doesn’t just make your code cleaner, it directly improves your app’s performance.
1. Aggregate Metrics
A common pattern is calculating both sum and count separately:
// language: ruby # Before pipeline_sum = PipelineRun.sum(:time_to_results_finalized) pipeline_count = PipelineRun.count
Each call triggers a separate query. You can combine both metrics in a single SQL scan:
// language: ruby # After pipeline_sum, pipeline_count = PipelineRun.pick( Arel.sql("SUM(time_to_results_finalized)"), Arel.sql("COUNT(*)") )
✅ Only 1 query
✅ Postgres calculates both in the same scan
2. Counting Conditional Subsets
If you’re counting filtered subsets, don’t run one query per condition.
// language: ruby # Before active_count = User.where(active: true).count inactive_count = User.where(active: false).count
Use Postgres FILTER to compute both in a single pass:
// language: ruby # After active_count, inactive_count = User.pick(Arel.sql(" COUNT(*) FILTER (WHERE active = TRUE), COUNT(*) FILTER (WHERE active = FALSE) "))
✅ Only 1 query
✅ Postgres calculates both in the same scan
We can use it with more complex conditions:
// language: ruby User.pick(Arel.sql(" COUNT(*) FILTER (WHERE last_login_at > NOW() - INTERVAL '30 days') AS recent_users, COUNT(*) FILTER (WHERE confirmed = FALSE) AS unconfirmed_users "))
3. Using .group for Grouped Metrics
Grouping is another easy win. We often loop over values and count them separately:
// language: ruby # Before statuses = {} ["draft", "published"].each do |s| statuses[s] = Post.where(status: s).count end
Rails can do it all in one query:
// language: ruby # After statuses = Post.group(:status).count # => { "draft" => 12, "published" => 42 }
✅ Only 1 query
✅ Returns a hash directly
✅ Scales linearly even with many groups
4. Loading Metadata & Associated Totals Together
When showing project stats, developers often query separately:
// language: ruby # Before project = Project.find(1) tasks_count = project.tasks.count members_count = project.members.count
Three queries total. You can aggregate directly with joins:
// language: ruby # After project = Project .left_joins(:tasks, :members) .where(id: 1) .select("projects.*, COUNT(DISTINCT tasks.id) AS tasks_count, COUNT(DISTINCT members.id) AS members_count") .group("projects.id") .first
✅ Only 1 query
✅ You can access
Conclusion
Rails makes it easy to express queries cleanly, but small inefficiencies add up fast. When you notice multiple .sum , .count , or .where calls in a row, ask yourself:
"Can this be done in one SQL pass?"
"Can this be done in one SQL pass?"
Related blogs

Quick Test Your IP Knowledge
You don’t need to be a software engineer to have heard of IP addresses. They pop up everywhere in our digital lives, from setting up Wi-Fi to troubleshooting connection issues. In this post, I’ve collected some common questions so you can quickly che...
Software Engineer
Software Engineer


Choose the Correct HTTP Status Codes for CRUD APIs
When building REST APIs, many people default to returning 200 OK for everything. But HTTP provides a rich set of status codes that communicate exactly what happened. Using them correctly makes your API more predictable, debuggable, and self-documenti...
Software Engineer
Software Engineer
