あるMySQLインスタンスで検証のためにschema(database)をコピーしてほしい。というリクエストを受けたときに最速で対応する方法は何か検証してみました。
MySQLにschemaをコピーするコマンドはありません。 schemaをコピーする方法として例えば以下の5つがあります。同じMySQLインスタンス上でschemaをコピーするならどの方法が最速でしょうか?
- INSERT INTO ... SELECT ...
- mysqldumpしてrestore
- mydumper/myloaderでdump&insert
- xtrabackupしてrestore
- Transporable Tablespaceでdump & import
アプリケーション開発者視点で実行しやすい方法から、DBAなどインフラエンジニアの権限(*1)がないと実行が難しい方法の順で並べてみました。
schema Aをコピーしてschema Bを作成した場合を想定して手順を書くと大体以下になります。
(本番環境でサービス中にこういった作業をすることを想定していないので、レプリケーションやファイルフォーマットなどをどう扱うかについては考慮していません)
INSERT INTO ... SELECT ...
新しいschemaでCREATE TABLE LIKE ...
でtableを用意し、INSERT INTO ... SELECT
でデータを入れていきます。
CREATE DATABASE B
CREATE TABLE ${tbl} LIKE A.${tbl}
でAの全テーブルをschema Bに作成INSSERT INTO B(col1, col2, ...) SELECT * FROM A
mysqldumpしてリストア
mysqldumpでbackupを作成し、元のテーブルをrenameして移動した上でrestoreします。
backupファイルのCREATE DATABASE A
部分やUSE A
の部分をsed等で書き換えても良いですが、データ量が多いとRENAME TABLEしていったほうが早いです。
CREATE DATABASE B
CREATE TABLE ${tbl} LIKE A.${tbl}
でAの全テーブルをschema Bに作成mysqldump --databases A > bk.dump
でダンプ- Aの全テーブルをBに移動 (
RENAME TABLE A.${tbl} TO B.${tbl}
) - ダンプしたファイルをリストア
mysql < bk.dump
mydumper/myloader
mysqldumpとやりたいことは同じですが、mydumper/myloaderを利用することで並列でdump, loadができます。
mydumper/myloaderのそれぞれのコマンドで--threads
を指定して並列度を調整して実行します。
CREATE DATABASE B
mydumper --database A --outputdir ${mydir}
でダンプmyloader -d ${mydir}
でロード
xtrabackup
xtrabackupでスキーマ指定のbackupを取り、restoreします。
schema指定やtable指定のbackup, restore方法は本家のブログが詳しいです。
CREATE DATABASE B
CREATE TABLE ${tbl} LIKE A.${tbl}
でAの全テーブルをschema Bに作成ALTER TABLE B.${tbl} DISCARD TABLESPACE
でBの全テーブルスペースをdiscardxtrabackup --backup --dataabses=A
でバックアップ作成xtrabackup --prepare --export
でプリペア(バックアップ中の更新を適用)- プリペアで作成されたibdファイル, cfgファイルをBのディレクトリにコピー
ALTER TABLE B.${tbl} IMPORT TABLESPACE
でインポート
Transporable Tablespaceでdump & import
Transporable TablespaceについてはMySQLのリファレンスマニュアルの"15.6.1.3 InnoDB テーブルのインポート"が詳しいです。
CREATE DATABASE B
CREATE TABLE ${tbl} LIKE A.${tbl}
でAの全テーブルをschema Bに作成ALTER TABLE B.${tbl} DISCARD TABLESPACE
でBの全テーブルスペースをdiscardFLUSH TABLES ${tbls} FOR EXPORT
でAの全テーブルをフラッシュ- フラッシュで作成されたcfgファイル, ibdファイルをBのディレクトリにコピー
ALTER TABLE B.${tbl} IMPORT TABLESPACE
でインポート
実験
上記の5つの方法をシェルスクリプトにし、100テーブル合計約150GBの環境でどれくらいの時間で完了するかを試してみた結果、下の図のようになりました。 この図では一番時間のかかったmydumpを利用した方法にかかった時間を100として、それぞれの方法で完了までにかかった時間を示しています。
mysqldumpの方法と比較して、xtrabackupの方法で約1/30, Transportable Tablespaceで1/35程度の時間で完了しました。
この実験ではinnodb_buffer_pool_dump_at_shutdown
及びinnodb_buffer_pool_load_at_startup
をOFFにして、各方法の実験前にMySQLを再起動したことで特に上記の方法に有利になった可能性はありますが、これらがONだったとしてもそれほど差はなかったと思います。
状況に応じて上記の方法のどれが最適かは異なると思いますが、同じインスタンス中ではコピーする方法によってかなり差があることがわかりました。 IOがどう発生するかを考えるとだいたい予想はつきますが、ここまで差が出るとは思わなかったのでブログにしました。(binlog = off, innodb_flush_log_at_trx_commit = 2です)
各方法でとったスクリプトについては後日別の記事にしたいと思います。(もう眠い)
(*1) サーバへのアクセス権限やMySQLアカウントの権限
.