Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/pawurb/activerecord-analyze
Add EXPLAIN ANALYZE to Rails Active Record query objects
https://github.com/pawurb/activerecord-analyze
Last synced: 2 days ago
JSON representation
Add EXPLAIN ANALYZE to Rails Active Record query objects
- Host: GitHub
- URL: https://github.com/pawurb/activerecord-analyze
- Owner: pawurb
- License: mit
- Created: 2018-03-11T19:03:39.000Z (over 6 years ago)
- Default Branch: main
- Last Pushed: 2024-02-25T21:37:28.000Z (9 months ago)
- Last Synced: 2024-10-31T15:15:04.671Z (11 days ago)
- Language: Ruby
- Size: 69.3 KB
- Stars: 220
- Watchers: 4
- Forks: 10
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE.txt
Awesome Lists containing this project
README
# ActiveRecord Analyze [![Gem Version](https://badge.fury.io/rb/activerecord-analyze.svg)](https://badge.fury.io/rb/activerecord-analyze) [![GH Actions](https://github.com/pawurb/activerecord-analyze/actions/workflows/ci.yml/badge.svg)](https://github.com/pawurb/activerecord-analyze/actions)
This gem 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](https://raw.githubusercontent.com/pawurb/activerecord-analyze/main/query-plan.png)
## Installation
In your Gemfile:
```ruby
gem 'activerecord-analyze'
```
## Options
The `analyze` method supports the following EXPLAIN query options ([PostgreSQL docs reference](https://www.postgresql.org/docs/12/sql-explain.html)):
```
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:
```ruby
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:
```ruby
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)```
### Analyzing raw SQL queries
You can also use a raw SQL query string to generate an EXPLAIN ANALYZE output:
```ruby
query = "SELECT * FROM users WHERE email = '[email protected]'"puts ActiveRecordAnalyze.analyze_sql(query, { format: :json })
# [
# {
# "Plan": {
# "Node Type": "Seq Scan",
# "Parallel Aware": false,
# "Relation Name": "users",
# "Alias": "users",
# "Startup Cost": 0.00,
# "Total Cost": 18.75,
# "Plan Rows": 4,
# "Plan Width": 88,
# "Actual Startup Time": 0.010,
# "Actual Total Time": 0.018,
# "Actual Rows": 0,
# "Actual Loops": 1,
# "Filter": "((email)::text = '[email protected]'::text)",
# "Rows Removed by Filter": 0
# },
# "Planning Time": 0.052,
# "Triggers": [
# ],
# "Execution Time": 0.062
# }
# ]
```This feature is helpful in analyzing SQL queries extracted from the logs.
### Disclaimer
It is a bit experimental and can break with new Rails release.