Railsコンソールでクエリキャッシュをデフォルトで無効化
Rails 8.1では、rails console実行時のActive Recordクエリキャッシュがデフォルトで無効になりました。これにより、コンソールでのクエリ結果が常に最新のデータベース状態を反映するようになります。
背景
#56297のマージ後、Railsコンソールではデフォルトでクエリキャッシュが有効になっていました。しかし、これが#56473で報告された問題を引き起こしていました。
コンソールでの対話的な作業では、同じクエリを複数回実行して結果の変化を確認することが一般的です。クエリキャッシュが有効だと、データベースの状態が変わっても古いキャッシュ結果が返されるため、開発者が混乱する原因となっていました。
技術的な変更
新しいコマンドラインオプション
--query-cache(エイリアス:-q)オプションが追加されました:
class_option :query_cache, type: :boolean, aliases: "-q", default: false,
desc: "Enable the Active Record query cache for the session (ignored if --skip-executor or -w is used)"
クエリキャッシュの無効化処理
コンソール起動時に、Executorラップが有効で--query-cacheオプションが指定されていない場合、すべてのコネクションプールのクエリキャッシュを無効化します:
def perform
# ...
wrap_with_executor = !options[:skip_executor]
conditional_executor(wrap_with_executor, source: "application.console.railties") do
disable_query_cache_in_console! if wrap_with_executor && !options[:query_cache]
Rails::Console.start(Rails.application, options)
end
end
private
def disable_query_cache_in_console!
return unless defined?(ActiveRecord::Base)
ActiveRecord::Base.connection_handler.each_connection_pool.select(&:query_cache_enabled).each(&:disable_query_cache!)
end
この実装により、クエリキャッシュが有効なコネクションプールのみを対象にdisable_query_cache!を呼び出しています。
使用方法
デフォルト動作(クエリキャッシュ無効)
bin/rails console
この場合、クエリは常にデータベースに対して実行されます。
クエリキャッシュを有効にする
bin/rails console --query-cache
# または短縮形
bin/rails console -q
設計判断
Executorとの連携
--skip-executorオプションが指定された場合、--query-cacheオプションは無視されます。これは、Executorがクエリキャッシュのライフサイクル管理を担っているためです。Executorなしでクエリキャッシュを制御することは技術的に困難であり、予期しない動作を引き起こす可能性があります。
オプトアウト設計
従来の「デフォルトで有効」から「デフォルトで無効(オプトイン)」に変更されています。これは、コンソールでの主要なユースケース(データの確認とデバッグ)において、キャッシュによる混乱を避けることを優先した判断です。パフォーマンスが重要なバッチ処理などでは、明示的に--query-cacheを指定することで最適化できます。
コネクションプール単位の制御
実装ではeach_connection_poolを使用して、すべてのコネクションプールを対象にクエリキャッシュを無効化しています。これにより、マルチデータベース構成でも一貫した動作が保証されます。