Rails 5.2 fixes query caching in MySQL & PostgreSQL adapters

Sushant Mittal

Sushant Mittal

May 16, 2018

Prior to Rails 5.2, MySQL and PostgreSQL adapters had select_value, select_values & select_rows select_{value,values,rows} methods. They improve the performance by not instantiating ActiveRecord::Result.

However these methods broke query caching of ActiveRecord::FinderMethods#exists? method. Let's check the issue.

1>> User.cache do
2>>   2.times { User.exists?(1) }
3>> end
4
5User Exists (2.1ms)  SELECT  1 AS one FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
6
7User Exists (2ms)  SELECT  1 AS one FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
8

As we can see, query was not cached and sql was executed second time.

From Rails 5.2, MySQL and PostgreSQL adapters are no longer override select_{value,values,rows} methods which fix this query caching issue.

Also, the performance improvement provided by these methods was marginal and not a hotspot in Active Record, so this change was accepted.

Let's check query caching of ActiveRecord::FinderMethods#exists? after the change.

1>> User.cache do
2>>   2.times { User.exists?(1) }
3>> end
4
5User Exists (2.1ms)  SELECT  1 AS one FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
6
7CACHE User Exists (0.0ms)  SELECT  1 AS one FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]

Now, query has been cached as expected.

This change has been backported in rails 5.1 from version 5.1.2 as well.

If this blog was helpful, check out our full blog archive.

Stay up to date with our blogs.

Subscribe to receive email notifications for new blog posts.