クエリのパフォーマンスチェックに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内で完結できるって便利ですよね。
これで、パフォーマンスチューニングがはかどりそうです。