- Ruby / Rails関連
Rails 7.1: ActiveRecord::Relation#explainに:verboseや:analyzeオプションが追加(翻訳)
Rails 7.1: ActiveRecord::Relation#explainに:verboseや:analyzeオプションが追加(翻訳)
Rails 7.1でActiveRecord::Relation#explain
メソッドが拡張されました。これによって、explain
にオプションを指定すると詳細なクエリプラン分析を出力できるようになります。
🔗 EXPLAINを理解する
Rails 7.1の新しいオプションを詳しく見る前に、Active Recordのexplain
メソッドの目的と利用法を軽くおさらいしておきましょう。explain
メソッドは、データベースオプティマイザが選択したSQLクエリの実行プランを取得するのに使われます。これにより、データベースがクエリをどのような意図で実行しているか(操作の実行順、利用するインデックス、見積もりコストなど)についての洞察を得られます。
クエリプランを分析することで、パフォーマンス上のボトルネックの特定、データベーススキーマ設計の最適化、微調整による効率の向上が行なえます。しかしRails 7.1より前は、explain
メソッドで出力できる詳細度に限りがありました。
🔗 クエリプランの詳細分析を取得するオプション
Rails 7.1のexplain
メソッドにオプションを渡せるようになったことで、explain
の出力をカスタマイズしてより詳細なクエリプラン分析を得ることが可能になります。
生SQLでも同様のオプションが利用可能ですが、利用するデータベースによってオプションが異なっている点が重要です。本記事ではPostgreSQLの例に特化することにします。それでは利用可能なオプションをいくつか見ていきましょう。
🔗 :analyze
:analyze
オプションを指定すると、(単なるプランの出力ではなく)ステートメントが実際に実行されます。続いて、実際のランタイム統計情報(プランノードごとの総実行時間や実際に返された総行数など)が表示に追加されます。
Service.where('age > ?', 25).joins(:user).explain(:analyze)
EXPLAIN (ANALYZE) SELECT "services".* FROM "services" INNER JOIN "users" ON "users"."id" = "services"."user_id" WHERE (age > 25)
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------------
Hash Join (cost=15.50..29.42 rows=103 width=232) (actual time=0.015..0.017 rows=0 loops=1)
Hash Cond: (services.user_id = users.id)
-> Seq Scan on services (cost=0.00..13.10 rows=310 width=232) (actual time=0.012..0.012 rows=0 loops=1)
-> Hash (cost=14.12..14.12 rows=110 width=8) (never executed)
-> Seq Scan on users (cost=0.00..14.12 rows=110 width=8) (never executed)
Filter: (age > 25)
Planning Time: 0.915 ms
Execution Time: 0.472 ms
🔗 :verbose
verbose
オプションは、実行プランごとのステップに関する追加情報など、より詳細な出力を提供します。追加される情報には、統計情報やコスト見積もりなどの関連する詳細情報が含まれます。
Service.where('age > ?', 25).joins(:user).explain(:verbose)
EXPLAIN (VERBOSE) SELECT "services".* FROM "services" INNER JOIN "users" ON "users"."id" = "services"."user_id" WHERE (age > 25)
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------------
Hash Join (cost=15.50..29.42 rows=103 width=232)
Output: services.id, services.user_id, services.provider, services.uid, services.access_token, services.access_token_secret, services.refresh_token, services.expires_at, services.auth, services.created_at, services.updated_at
Inner Unique: true
Hash Cond: (services.user_id = users.id)
-> Seq Scan on public.services (cost=0.00..13.10 rows=310 width=232)
Output: services.id, services.user_id, services.provider, services.uid, services.access_token, services.access_token_secret, services.refresh_token, services.expires_at, services.auth, services.created_at, services.updated_at
-> Hash (cost=14.12..14.12 rows=110 width=8)
Output: users.id
-> Seq Scan on public.users (cost=0.00..14.12 rows=110 width=8)
Output: users.id
Filter: (users.age > 25)
(11 rows)
PostgreSQLのEXPLAINについて詳しくは以下の公式ドキュメントを参照してください。
参考: PostgreSQL 15ドキュメント: EXPLAIN
詳しくは#47043を参照してください。
概要
元サイトの許諾を得て翻訳・公開いたします。
参考: 週刊Railsウォッチ20230214:
ActiveRecord::Relation#explain
にオプションを渡せるようになった参考: Rails API
explain
--ActiveRecord::Relation
参考: PostgreSQL 15ドキュメント:
EXPLAIN
参考: MySQL :: MySQL 8.0 リファレンスマニュアル :: 13.8.2
EXPLAIN
ステートメント