91
57

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

そのクエリ、ちゃんとチューニングされてる?Railsで確認する方法

Posted at

クエリのパフォーマンスチェックにMySQLのEXPLAINを使っている方も多いと思います(私もその一人です)。
RailsコードとMySQLの行き来が多く、時間がかかります。
もっと、開発スピードもあげたいものです・・・!😩

今回使うテーブル

  • Postsテーブル
名前 制約
id AUTO INCREMENT NOT NULL ( ※ プライマリーキーなので、INDEXあり)
title VARCHAR -
content TEXT -
user_id INTEGER NOT NULL, INDEX

よくやる方法(Rails ←→ MySQL)

  • Railsで、該当のモデルで.to_sqlし、SQLクエリを発行する
user_ids = [1, 2, 3]
Posts.where(user_id: user_ids).to_sql

=> SELECT `posts`.* FROM `posts` WHERE `posts`.`person_id` IN (1, 2, 3)
  • MySQLに何らかの方法でログインする
    • ご自由に!
      • コンソール
      • GUI
  • クエリの先頭にEXPLAINをつけて実行
mysql> EXPLAIN SELECT `posts`.* FROM `posts` WHERE `posts`.`person_id` IN (1, 2, 3)

+----+-------------+-------------+------+--------------------------------+------+---------+------+------+-------------+
| id | select_type | table       | type | possible_keys                  | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------------+------+--------------------------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | posts       | ALL  | index_posts_on_user_id         | NULL | NULL    | NULL | 1234 | Using where |
+----+-------------+-------------+------+--------------------------------+------+---------+------+------+-------------+
1 row in set (0.01 sec)

この結果を見て、チューニング。
RailsコードとMySQLの行き来が発生します。
非常に手間ですね😇

Railsだけで完結させる方法

あまり知られていないようですが、RailsではMySQLのEXPLAINを実行する.explainメソッドを提供しています。
(私もおとといくらいにRailsのコードを読んでいて気づきました。)

activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter
# ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter#explain
# https://github.com/rails/rails/blob/8b69e32412cc2867b5fdd9a33cf4e4e759057e95/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb#L178

def explain(arel, binds = [])
  # クエリの先頭に「EXPLAIN」をつける
  sql     = "EXPLAIN #{to_sql(arel, binds)}"
  start   = Time.now
  # クエリを実行する
  result  = exec_query(sql, "EXPLAIN", binds)
  elapsed = Time.now - start

  MySQL::ExplainPrettyPrinter.new.pp(result, elapsed)
end

Railsで、該当のモデルで.explainする

user_ids = [1, 2, 3]
Posts.where(user_id: user_ids).explain

=> EXPLAIN for: SELECT `posts`.* FROM `posts` WHERE `posts`.`person_id` IN (1, 2, 3)
+----+-------------+-------------+------+--------------------------------+------+---------+------+------+-------------+
| id | select_type | table       | type | possible_keys                  | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------------+------+--------------------------------+------+----!-----+------+------+-------------+
|  1 | SIMPLE      | posts       | ALL  | index_posts_on_user_id         | NULL | NULL    | NULL | 1234 | Using where |
+----+-------------+-------------+------+--------------------------------+------+---------+------+------+-------------+
1 row in set (0.01 sec)

explainメソッドで返ってくる結果は、MySQLで表示されているものと同じなのです。

EXPLAINの読み方

読み方に関しては、Qiitaやブログでまとめられているので、あえて書きません。
オススメは、下記のサイトがわかりやすいです。

参考にどうぞ!

まとめ

今までMySQLで確認していたことが、Rails内で完結できるって便利ですよね。
これで、パフォーマンスチューニングがはかどりそうです。

読んだコード

91
57
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
91
57

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?