Rails 8 adds explain support to ActiveRecord::Relation

railsFebruary 07, 2024Dotby Alkesh Ghorpade

The explain method in Rails' ActiveRecord is a powerful tool for understanding how your database executes your queries. It allows you to peek under the hood and see the exact SQL query that will be sent to the database and the execution plan the database has chosen to retrieve the data. It provides insight into the sequence of operations, indexes used, and estimated costs involved in executing a particular query.

The explain method was first introduced in Rails 3.2.0. Rails 7.1 allows passing :verbose and :analyze options to the ActiveRecord explain method. Please refer to our previous blog post to learn more about this feature.

While the explain method worked well, providing insights into the database queries, it failed for queries that returned an ActiveRecord::Relation.

Before Rails 8.0

Let's say you have a Rails application with the Post and Comment model. The post model has a boolean column published. You can use the explain method as shown to understand the execution plan of the query.

> Post.where(published: true).explain
  Post Load (0.2ms)  SELECT "posts".* FROM "posts" WHERE "posts"."published" = $1  [["published", true]]
 => 
EXPLAIN SELECT "posts".* FROM "posts" WHERE "posts"."published" = $1 [["published", true]]
                        QUERY PLAN
----------------------------------------------------------
 Seq Scan on posts  (cost=0.00..15.40 rows=270 width=121)
   Filter: published
(2 rows)

The problem arrives when you try to use it on ActiveRecord methods like count, last, or pluck.

> Post.where(published: true).count.explain
  Post Count (0.5ms)  SELECT COUNT(*) FROM "posts" WHERE "posts"."published" = $1  [["published", true]]
(irb):3:in `<main>': undefined method `explain' for 2:Integer (NoMethodError)

Post.where(published: true).count.explain
                                 ^^^^^^^^

> Post.where(published: true).pluck(:id).explain
  Post Pluck (0.2ms)  SELECT "posts"."id" FROM "posts" WHERE "posts"."published" = $1  [["published", true]]
(irb):5:in `<main>': undefined method `explain' for [1, 2]:Array (NoMethodError)

Post.where(published: true).pluck(:id).explain
                                      ^^^^^^^^

While the explain method is a valuable tool for understanding query performance in Rails' ActiveRecord, it currently has limitations with methods like last, pluck, and count that return single values or arrays instead of full relations. This lack of relational context makes it harder to analyze the query's execution plan and identify potential optimizations.

Rails 8.0

Rails 8.0 adds explain support to ActiveRecord::Relation. This change allows the developer to run the explain function on the below methods.

1. average
2. count
3. first
4. last
5. maximum
6. minimum
7. pluck
8. sum

The post queries that failed before Rails 8.0 will run safely without raising any errors.

> Post.where(published: true).count.explain
  EXPLAIN SELECT COUNT(*) FROM "posts" WHERE "posts"."published" = $1  [["published", true]]

> Post.where(published: true).pluck(:id)
  EXPLAIN SELECT "posts"."id" FROM "posts" WHERE "posts"."published" = $1  [["published", true]]  

Note:

This change breaks the existing functionality of the explain method. You need to use inspect after the explain method.

> Post.all.explain.inspect

Luckily, this limitation poses no issue in interactive environments like IRB, where inspect automatically provides valuable insights.

To know more about this feature, please refer to this PR.

Closing Remark

Could your team use some help with topics like this and others covered by ShakaCode's blog and open source? We specialize in optimizing Rails applications, especially those with advanced JavaScript frontends, like React. We can also help you optimize your CI processes with lower costs and faster, more reliable tests. Scraping web data and lowering infrastructure costs are two other areas of specialization. Feel free to reach out to ShakaCode's CEO, Justin Gordon, at justin@shakacode.com or schedule an appointment to discuss how ShakaCode can help your project!
Are you looking for a software development partner who can
develop modern, high-performance web apps and sites?
See what we've doneArrow right