[Awesome Ruby Gem] Use activerecord-analyze gem to analyze Active Record query in the PostgreSQL database

activerecord-analyze

activerecord-analyze adds an analyze method to Active Record query objects. It executes EXPLAIN ANALYZE on a query SQL.

You can check out this blog post for more info on how to debug and fix slow queries in Rails apps - https://pawelurbanek.com/slow-rails-queries.

The following format options are supported :json, :hash, :yaml, :text, :xml. Especially the :json format is useful because it let’s you visualize a query plan using a visualizer tool - https://tatiyants.com/pev/#/plans/new.

PG Query visualizer plan

Installation

You can install it as a gem:

1
$ gem install activerecord-analyze

or add it into a Gemfile (Bundler):

1
2
3
4
5
6
7
8
# Gemfile

# Put gems used only for development or testing in the appropriate group in the Gemfile
group :development do
# pawurb/activerecord-analyze: Add EXPLAIN ANALYZE to Rails Active Record query objects
# https://github.com/pawurb/activerecord-analyze
gem 'activerecord-analyze', '0.9.1'
end

Then, run bundle install.

1
$ bundle install

Usages

Options

The analyze method supports the following EXPLAIN query options (PostgreSQL docs reference):

1
2
3
4
5
6
7
buffers: [ boolean ]
verbose: [ boolean ]
costs: [ boolean ]
settings: [ boolean ]
timing: [ boolean ]
summary: [ boolean ]
format: { :text | :json | :xml | :yaml | :pretty_json }

You can execute it like that:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
puts User.all.analyze(
format: :pretty_json, # :pretty_json format option generates a formatted JSON output
verbose: true,
costs: true,
settings: true,
buffers: true,
timing: true,
summary: true
)

# EXPLAIN (FORMAT JSON, ANALYZE, VERBOSE, COSTS, SETTINGS, BUFFERS, TIMING, SUMMARY)
# SELECT "users".* FROM "users"
# [
# {
# "Plan": {
# "Node Type": "Seq Scan",
# "Parallel Aware": false,
# "Relation Name": "users",
# "Schema": "public",
# "Alias": "users",
# "Startup Cost": 0.00,
# "Total Cost": 11.56,
# "Plan Rows": 520,
# "Plan Width": 127,
# "Actual Startup Time": 0.006,
# "Actual Total Time": 0.007,
# "Actual Rows": 2,
# "Actual Loops": 1,
# "Output": ["id", "team_id", "email"],
# "Shared Hit Blocks": 1,
# "Shared Read Blocks": 0,
# "Shared Dirtied Blocks": 0,
# "Shared Written Blocks": 0,
# "Local Hit Blocks": 0,
# "Local Read Blocks": 0,
# "Local Dirtied Blocks": 0,
# "Local Written Blocks": 0,
# "Temp Read Blocks": 0,
# "Temp Written Blocks": 0,
# "I/O Read Time": 0.000,
# "I/O Write Time": 0.000
# },
# "Settings": {
# "cpu_index_tuple_cost": "0.001",
# "cpu_operator_cost": "0.0005",
# "cpu_tuple_cost": "0.003",
# "effective_cache_size": "10800000kB",
# "max_parallel_workers_per_gather": "1",
# "random_page_cost": "2",
# "work_mem": "100MB"
# },
# "Planning Time": 0.033,
# "Triggers": [
# ],
# "Execution Time": 0.018
# }
# ]

Optionally you can disable running the ANALYZE query and only generate the plan:

1
2
3
4
5
6
User.all.analyze(analyze: false)

# EXPLAIN ANALYZE for: SELECT "users".* FROM "users"
# QUERY PLAN
# ----------------------------------------------------------
# Seq Scan on users (cost=0.00..15.20 rows=520 width=127)

References

[1] pawurb/activerecord-analyze: Add EXPLAIN ANALYZE to Rails Active Record query objects - https://github.com/pawurb/activerecord-analyze

[2] activerecord-analyze | RubyGems.org | your community gem host - https://rubygems.org/gems/activerecord-analyze/

[3] Fix Slow Active Record SQL Queries in Rails [Step by Step] - https://pawelurbanek.com/slow-rails-queries

[4] Postgres EXPLAIN Visualizer (pev) - https://tatiyants.com/pev/#/plans/new

[5] pawurb/rails-pg-extras: Rails PostgreSQL database performance insights. Locks, index usage, buffer cache hit ratios, vacuum stats and more. - https://github.com/pawurb/rails-pg-extras

[6] PostgreSQL: The world’s most advanced open source database - https://www.postgresql.org/