Back to Blog

Rails 5.2 fixes query caching in MySQL & PostgreSQL adapters

on 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.


You might also like

If you liked this blog post, check out similar ones from BigBinary