この記事は
Ruby on Railsのカレンダー | Advent Calendar 2021 - Qiita 18日目の記事です。
昨日に引き続き、空いていたので参加してみました。
背景
昨日、Advent Calender Ranking 2021 に New RelicをRailsアプリにinstallしたところ、DB部分で速度が出ていないことが分かりました。
当初、このRailsアプリはHerokuにデプロイし、postgres add-onn を利用していましたが、レコードの上限数を超えたため、とりあえず無料で使えるElephant SQLへ乗り換えていました。
(この辺の話は以下に記載)
herokuのRailsアプリでDBをElephantSQLにしてみた - rochefort's blog
こいつが若干遅いということは分かっていたのですが、今はHerokuからVPSに移行しているので、今回ElephantSQLからDBの移行を行いました。
以下、本題。
DBの選択
PostgreSQLかMySQLサービスを使っても良いのですが、メモリ使うし、
まぁ、sqlite使って壊れても割と簡単にデータ復旧できるし問題ないだろうという判断でsqliteへの移行を行うことにしました。
ElephantSQLからのdump取得
これは簡単で、consoleからボタンひとつで取り出せます。
sqliteへの取り込み
ここが今回はまりました。
dumpはsql形式なので、ちょこっと編集すればsqliteに取り込むのも簡単だろうと思っていましたが、dumpはcopy句を使っていて、これが現在のsqliteでは使えません。
他にもPostgreSQLのdumpをsqliteに変換できるJava系のツールも公開されていたので試してみましたが、古いようで動きませんでした。
後は、csvに変換して取り込む方法ですが、NULLが空白になっちゃうし(アプリケーション的には問題ないけど、なんとなく嫌)、他の方法を思索したところ、 Rails6のMultiple Databaseの機能を使って移行できるのではないかという考えが思いつきました。
ご参考)
Active Record で複数のデータベース利用 - Railsガイド
やってみる
事前準備として、ElephantSQLのdumpを移行元PostgreSQLとしてimportしておきます。
また、移行先のsqliteも必要ですので、一時的にdatabase.ymlを変更し新しいDBを作って、rails db:migrate
しておきます。
multiple DB設定
config/database.yml
に移行先(sqlite)、移行元(PostgreSQL)の定義をしておきます。
development: # 移行先 primary: database: db/production.sqlite3 adapter: sqlite3 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> # 移行元 primary_replica: adapter: postgresql encoding: unicode database: postgres-rails-app pool: 5 username: rochefort password:
ApplicationRecordに primary、primary_replicaのデータベースロール(writing, reading)を設定するだけ。
class ApplicationRecord < ActiveRecord::Base self.abstract_class = true connects_to database: { writing: :primary, reading: :primary_replica } end
移行
後はrails consoleで読み書きするだけです。
書き込みは、Rails6から利用できる insert_all
を活用。
def copy_table(klass) list = nil ActiveRecord::Base.connected_to(role: :reading) { list = klass.all } ActiveRecord::Base.connected_to(role: :writing) { klass.insert_all(list.map(&:attributes)) } end # example copy_table(Author)
感想
という感じで、サクッとできました。
当初考えていたdumpのsqlを手動で変更する手間もないですし、
csv経由でやるより簡単な印象です。
こんなことのためにMulti DB使ってるのは私ぐらいでしょうが、RailsのMulti DB自体は設定も簡単なので良いですね。