(なるべくお手軽に)MySQLの自動バックアップをテーブル単位で取ってみたい

この記事はだいぶ前に書かれたものなので情報が古いかもしれません
あちゃくらりょうこ復活ッッ

この記事を三行にまとめると

MySQLのバックアップをテーブルごとに取りたい
CakePHPを使えばわりとお手軽
CakePHPを使わなくてもわりとお手軽
データベースのバックアップを自動で取るよう、cronで設定したりとかすることがあると思います。

データが少ない場合はデータベースを丸ごと一つのバックアップファイルにしちゃっても良いと思うんですが、段々とデータが増えてくると、ファイルを分割しておきたくなるかもしれない。うっかりデータが丸ごと吹っ飛んでしまって、バックアップを使って一気に復活させる場合でも、ファイルサイズが大きいと作業も大変になるかもしれないから、テーブルごとにバックアップファイルを作っておいた方が良い場合もあるでしょう。あの優秀なバックアップであった朝倉さんだって、大きい状態では復活できませんでしたからね。

僕の場合だとよくあるのが、お客さんからのクレームが来たときに、過去のバックアップデータを漁って、そのときどんなデータが入ってたか調べるみたいなやつ。よくあると言いつつ実際はそんなにないんですけど「おいデータが消えてんぞ、どうなってんだゴルァ!」とか「データ削除したら余計なものまで消えちゃったぞ、どうなってんだゴルァ!」とか「モザイク消し使ったけど全然消えてねーぞ、どうなってんだゴルァ!」みたいなクレームが来ることがあります。そういうときにバックアップデータを漁ったりして、システムのバグによって消えてしまったものなのか、運用側のミスでうっかり消してしまったものなのか、モザイクを消す装置に欠陥があったのか、装置の使い方が間違ってて上手くモザイクが消えなかったのか、そういうのを確かめたりするわけですね。

システムにバグがあった場合はしかたありません。とにかく頭を下げて謝って、データを元に戻せるのであればすかさず元に戻して謝って、バグを修正して謝って、損害金を払う必要があるときはそれを払って謝って、菓子折りの一つでも差し入れて謝って、どうしてもモザイクが消えないという場合にはこっそり無修正の動画をプレゼントして謝るしかない。でも明らかに人為的に削除した痕跡が見つかれば「システムエラーじゃありまっせーん。べろべろばー。顔を洗って歯を磨いてシャワーを浴びて服を着替えて髪型をセットして朝食を食べて食後にモーニングコーヒーを飲んでから出直して来てもらえますぅ?」って、こっちもでかい態度に出られるわけです。

最初の頃はデータの量が少ないから、一つのバックアップファイルの中から適当に探すってこともできたんですが、段々とデータが増えて来ると、それも難しくなってくる。自分が見たいデータが入ってるテーブルがファイルのどの辺にあるのかっていう当たりをつけるところから、まず難しくなってくる。

そこで、じゃあバックアップはテーブル単位で取るようにしようじゃないかと。データ量が多くなれば、テーブル単位であっても検索は難しくなるけれど、分割されてないよりは良いよね。

ってことで、やってみます。

ぶっちゃけたいしたことはやってないです。難しいことは何も考えず、とりあえずテーブルごとにSQLをダンプするだけなら10行もいらない。

ちなみに、CakePHP2系で開発し、データベースにはMySQLを使っているという前提でおなしゃす。

$db = ConnectionManager::getDataSource('default');
$tables = $db->listSources();
$config = $db->config;

foreach($tables as $table) {
  exec('mysqldump --host='.$config['host'].' --user='.$config['login'].' --password='.$config['password'].' '.$config['database'].' '.$table.' > '.$table.'.sql');
  exec('gzip -f '.$table.'.sql');
}

こんな感じで「テーブル名.sql」というバックアップファイルを作成することができます。ついでに今回は、そのファイルをgzipで圧縮してみました。cronで定期的にバックアップを取りたいなら、こいつをシェルに書いてやればオッケーですね。

CakePHPに「ConnectionManager」ってクラスがあるんですが、その中にある「getDataSource()」ってやつを使えば、データベースに関する情報が取れます。引数に入れている「default」は、database.phpの「$default」で設定しているデータベースの情報を取得するぜよってことです。自分で任意に使用しているデータベースの変数を変えているなら、それに合わせて引数の中身も変える必要がある。

「listSources()」というのは、テーブル名の一覧をリストで取得する関数です。なので、上記のコードで言うところの「$tables」には、全テーブル名のリストが入ってます。「$config」の方はデータベースの接続情報が入ってます。

CakePHPを使ってるなら、モデルを使って全テーブルのリストを取得することもできると思いますが、今回みたいな場合は、こっちの書き方の方が個人的には楽かなーと。

「mysqldump」っていうのがバックアップを作成するためのコマンドなのですが、データベース名の後ろにスペースを空けてテーブル名を入れると、そのテーブルのデータだけをダンプできます。省略すれば全テーブルのデータを一挙にダンプする。他にもこのコマンドにはいろいろとオプションがあるみたいなんですが、今回はそーゆーのはつけませんでした。てゆーかよく分かんね。

それから今回はやってないですが、全部のテーブルではないけど複数のテーブルをまとめてバックアップ取りたいって場合は、スペースで区切って記述すればいけるっぽい。

//データベースを丸ごと
# mysqldump データベース名 > backup.sql

//テーブルを一つだけ
# mysqldump データベース名 テーブル1 > backup.sql

//複数のテーブルをまとめて
# mysqldump データベース名 テーブル1 テーブル2 テーブル3 > backup.sql

コマンドだけ書くとこんなんですかね。






今までデータベースのバックアップは出来合いのプラグイン的なものを利用させてもらっていたんですが、それはテーブル単位でのバックアップ作成には対応していなくて、しかもPHPじゃなくて、拡張子が「.sh」のシェルスクリプト?とかいうやつで書かれてたので、いまいちいじり方もよく分からなくて、ずっとほったらかしてました。

でもこんな程度で良けりゃ、PHPを使って(今回はCakePHPも使いましたが)バックアップを作成できるみたいです。何でもやってみるもんですなぁ。

ってなことで、とりあえずダンプができりゃ何でも良いってんなら、CakePHPを使わなくてもテーブルのリストさえ取得できれば、適当にforeachで回してあとはmysqldumpするだけなんで、たぶんお手軽だと思うんですが……どうでっしゃろ。

PHPべた書きなら、mysql_query()とかPDO_MYSQLやMySQLiのquery()とかを使って「SHOW TABLES FROM データベース名」ってクエリを投げればリストを取得できるはず……今回は試してないけど。
 もしかしたら何か関連しているかも? 
 質問や感想などお気軽にコメントしてください