オープニングトーク
こんにちはpnpkです。
買掛業務改善クラウドサービス「トッツゴー」の設計・開発を担当しています。
そんなトッツゴーではRuby on Railsを利用しています。
何回かに分けて、Ruby on Railsを利用した開発における開発効率を上げるちょっとした工夫をご紹介する企画の続編です。
今回はDatabaseアクセスの最適化を行なっていく上で作成した補助スクリプトを紹介出来ればと思います。
視覚的にDBアクセス状況を確認したい
開発中、N+1になっていないか?や、想定通りのクエリが発行出来ているか?などを日々注意しながら開発していることだと思います。
私はそういったデバッグを視覚的に行うための補助ツールとして、Rails Panelを愛用していました。Rails PanelはGoogle Chromeのエクションテンションとして動作し、Chrome上からデバッグ情報を参照出来るようにする、極めて優秀なツールです。
ところが最近Rails Panelの更新が途絶えてしまい、さらに私の環境ではうまく動作しなくなってしまいました。また、アプリケーションのバージョンアップでトータル実行されたSQL実行数が見られなくなったり、やりたい事が実現出来なくもなっていました。
そこで、私のやりたい事を実現するために新たにスクリプトを作ってみました。
sql_query_counterで出来ること
sql_query_counterを設定すると、アクセスしたコントローラのメソッド単位で以下の情報をコンソール表示出来るようになります。
- レスポンスタイムの表示(ロジックとDB)
- SQLクエリ実行回数
- リードレプリカ対応版はどちらのDBに何回SQLクエリが実行されてかも表示します
- 実行されたSQLクエリ
- 後述の
SQL_QUERY_COUNTER_VERBOSEをtrueにすることで、具体的にどのSQLが実行されたかを表示します
- 後述の
実装中や、パフォーマンス改善を行う際に有用に使ってもらえるんじゃないかと思います。
使い方
下記のスクリプトをsql_query_counter.rbのように適当な名前をつけて、config/initializersに保存します。
ENVの値でSQL_QUERY_COUNTER_VERBOSEを付けているので、必要に応じて直接指定するか、ENVを設定してみてください。
SQL_QUERY_COUNTER_VERBOSEがtrueの場合、SQLクエリを表示します。
その他もいくつか設定できるようにしているので、好みの設定を使いながら探ってみてください。
config = ActiveSupport::OrderedOptions.new
config.enabled = true
config.console_output = true
config.log_output = false
# クエリ数の閾値(この数を超えたら警告表示)
config.warning_threshold = 50
# SQLクエリの内容も表示する場合はtrueに設定
# 環境変数 SQL_QUERY_COUNTER_VERBOSE で制御(デフォルト: false)
config.verbose = ENV.fetch('SQL_QUERY_COUNTER_VERBOSE', 'false') == 'true'
# 除外するクエリタイプ
config.exclude_types = ['SCHEMA', 'CACHE']
# コントローラを限定する場合に登録
config.only_controllers = []
# コントローラを除外する場合に登録
config.except_controllers = []
warning_thresholdはデフォルト50にしています。この値を超えたコントローラメソッドがあった場合に、画面上に警告表示が出て、もっと頑張ってSQL実行回数を減らすよう促します。環境によって、増減させてみてください。
ppp_coloring
また、コード中で私の作成したppp_coloringというGEMを利用している箇所があるため、必要に応じてppに書き換えるか、これを機にppp_coloringを是非利用してみてください。
シングルDB版
一般的なシングル構成のDBで利用出来るように作ってあります。MYSQLで動作させている環境で使っているので、環境によって動かない場合もあるかもしれませんが、その場合は適宜コードを更新して使ってください。
リードレプリカ対応版
トッツゴーでは、より快適なユーザー体験を実現させるため、キャッシュの活用とリードレプリカからのデータ参照を積極的に行っています。Rails7以降の複数データベース対応が行われている環境なら、こちらを利用することで書き込み・読み込みDBそれぞれに対応します。
