さらに spec の実行を速くする
MySQL のデータを RAM Disk 上に置いて 3 倍の速度を達成したわけだが、さらなる高速化を考えた。
遅いところ
経験上、fixture を何度も読込んでいると遅いことがわかっている。fixture を before(:each) ではなく、before(:all) で読み込むようにすれば、回数が減るので速くなる。
ちなみに fixture は指定されたディレクトリ配下のファイル郡が
MySQL 上の一つの DB の各テーブルに対応させた状態にして管理している。
読込の単位は、このディレクトリ毎としている。
fixture の読込を減らす
同じ fixture を何度も読み込んでいることが問題なわけで、最初に一回読み込んだら、その snapshot を取って、再読み込みの際は snapshot まで戻せばよい。
MySQL に snapshot 機能は存在しない。
よって、 fixture を登録しているところで次のような処理を行うことで、これを実現した。
- 過去に fixture が読込済みで無い場合
- 通常の fixture の登録処理を行う
- mysqldump で DB 全体をバックアップする
- fixture が読込済みの場合
- mysql コマンドでバックアップからリストアする
速度
さらに 1.5 倍の速度が達成された。
ちなみに mysql & mysqldump を TCP/IP 経由ではなく、UNIX DOMAIN Socket で接続すると 10 秒程度の向上がみられた(上記はこれを反映している)。
Ram DISK : 366 sec
fixture を dump & restore : 232 sec
さらにさらに速くする
以下は未検証。
MySQL には snapshot 機能は無いわけだが、 Transaction は条件を限定すればそれっぽく使えるはず。
普通だったら処理の完了後は commit され、再度テストに使える状態ではなくなる。でも commit せずに rollback すれば、テストデータ投入時と同じ状態になるため、再度テストに使うことができるようになるはずである。
今作っているシステムは Transaction の「入り」、「出(commit)」を独自の Class によって管理しているので、「出(commit)」の部分では何も行わないようにして、fixture の再読込みで行うようにすれば、これは実現可能であると思う。
また、多分 MySQL の commit は「commit 後に実際に DB のデータを書き換える」構成のようなので、この方法によってかなりの速度向上が見込めるかと思う。