2021年9月23日パーフェクト Ruby on Rails
複数のデータベースを扱う
Webアプリケーションの規模が大きくなるとしばしば応答速度の低下が問題になる事があり、ボトルネックになりやすいのはDBアクセスに関する部分という事がよくあります。
そういった問題を解決し、複数のDBを利用するgemパッケージとしてOctopusやswitch_pointなどがありましたが、Rails6.0からはRails標準機能として複数DBに対応しました。
複数DB対応で提供している機能
- 複数のprimaryデータベースと、それぞれに対応する1つのreplica
- モデルでのコネクション自動切り替え
- HTTP verbや直近の書き込みに応じたprimaryとreplicaの自動スワップ
- マルチブルデータベースの作成、削除、マイグレーション、やり取りを行うRailsタスク
これらの機能がユースケースと合致しない場合はOctopusやswitch_pointの使用を検討すると良いです。
2つのDBへ接続するには
config/database.ymlを記述する
default: $default adapter: sqlite3 pool: <%= ENV.fetch("RAILS_MAX_THREADS"){5} %> timeout: 5000 development: primary: <<: *default database: db/development.sqlite3 sub: <<: *default database: db/development_sub.sqlite3 migrations_paths: db/sub_migrate test: 略 production: 略
database.yml内のdevelopmentといった環境変数の下の階層として、各種DBの名称(どういう用途のDBかわかりやすい名称にする)を記述し、その中に接続情報を記述します。
そして、片方のDBにだけマイグレーションパスを指定します。これで異なるテーブルの定義を反映させられます。
この段階でdb:createを実行するとそれぞれのデータベースを作成可能です。
またdb:create:subとすると、subの方だけのデータベースを作成する事もできます。
この時点ではモデルを操作しても片方のDBしか参照できないので、特定のモデルと特定のDBを接続させたい場合は各モデルクラスでestablish_connectionを利用します。(establishは設立するという意味です)
役割を明確にするためにestablish_connectionを指定productionちあ抽象クラスを作成し、そのクラスを継承したモデルクラスを利用すると良いです。
# app/models/sub_base.rb class SubBase < ApplicationRecord self.abstract_class = true establish_connection :sub end # app/models/author.rb class Author < SubBase end
これでAuthorモデルを通じてレコードを作成した場合、subデータベースへ書き込みを行うようになりました。
self.abstract_class = trueが何かわからなかったので調べました。
ActiveRecord::Base を継承したクラスをモデルとして作成すると、Rails はそのクラス名に対応したデータベースのテーブルを自動的に探そうとします。対応するデータベースのテーブルを用意しない場合は、self.abstract_class = true を書く必要があります。ActiveRecord::Base を継承したクラスを作成し、さらにそのクラスを継承させたい場合に self.abstract_class = true が書かれるようです。
今回の場合Author.create
でデータを入れようとした場合に通常ではエラーが起きてしまうため、self.abstract_class = true
を記述する必要があります。
ひとこと
複数のデータベースを作成することはしたことがないのですが、いずれ使うときのためにひとつひとつ踏みしめて学んでいきます。