online schema change_for_mysql_casual
TRANSCRIPT
Online Schema Change
in mysql casual
自己紹介
• 名前:林 成敏(はやし なりとし)• ID:nhayashi || n_hayashi• 所属:DeNA
今回の発表
• Online Schema Change• Facebook で使われている(らしい)• 元はPHPで実装• 今回、perl で実装してみました
テーブルスキーマ変更方法
• サービスを止めてメンテナンス中に実行• 新しいテーブルスキーマを別テーブルに用意してアプリで
ダブルインサートしてrenameで切り替える• 諦める
問題点(サービス止めない場合)
• 気軽にALTER文を打つとテーブルロックがかかる• アプリ側の対応が必要で大変• どこまで更新処理をしたか既存データ移行後に全部追う必
要があり整合性の確認が大変
こうできれば幸せ
• サービス止めなくていい• エラー出さずによしなに更新してくれる• アプリ側の対応はなし• 当然、データの整合性は維持
MySQL::ChangeSchemaで幸せになろう
• github にあがってます• URL はのちほど
使い方
use MySQL::ChangeSchema;my $osc = MySQL::ChangeSchema->new(
db => "test",table => "test2",user => "root",pass => "root",
);$osc->connect();$osc->init();$osc->cleanup();eval {
$osc->execute("ALTER TABLE test2 MODIFY hoge varchar(512)");};if ($@) {
print $@."\n";$osc->cleanup;
}
データフロー
前置き
• いくつか条件付きでほぼ正常に動作します。• たぶん適材適所で使うべき
必要条件
• Primary key が定義されている• Foreign key が設定されていない• after insert/delete/update trigger が設定されていない• InnoDB のみサポート• 後方互換のある ALTER文のみ• レプリ構成の場合は カラムの ADD/DROP はレプリが止ま
る• (Disk I/O 等の性能に関しては考慮してません)
実行条件
• MySQL稼働サーバで実行• master/slave それぞれで実行• /var/lib/mysql への書き込み権限が必要• Alter/Lock_tables/Repl_*/Trigger 権限が必要• MySQL::ChangeSchema が入っていることw
実行時のTIPS
• local $MySQL::ChangeSchema::VERBOSE = 1;o 実行SQLすべてが出力されます。
SQL解説 ~ スナップショット
• START TRANSACTION WITH CONSISTENT SNAPSHOT;o セッション内において分離レベルを変更せず、コマンド発行時点のデータ状態を保持。
SQL解説 ~ テーブルロック
• LOCK TABLE t1 WRITE;o t1 テーブルへの更新をロックする。o ロック中の更新処理は Lock Wait 状態になる。
• UNLOCK TABLES;o ロックしているテーブルを開放する。
SQL解説 ~ アプリケーションロック
• SELECT get_lock('osc_lock', 0);o ロックを取得o 0 はロック待ちしない
• SELECT is_free_lock('osc_lock');o ロックが取得できるか確認
• do release_lock('osc_lock');o ロックを開放
SQL解説 ~ バイナリログ、トランザクション
• SET sql_log_bin = 0;o セッション内でバイナリログ出力を抑止
• SET session autocommit = [0|1];o セッション内でトランザクション有効/無効
SQL解説 ~ テーブル作成
• CREATE TABLE t2 LIKE t1;o primary key, index 含めた t1 テーブルと同じスキーマを作成
• CREATE TABLE t2 (id int) AS (SELECT hoge FROM t1 LIMIT 0);o カラムの型のみ 同じスキーマを作成
SQL解説 ~ トリガ AFTER INSERT
• CREATE TRIGGER insert_triggerAFTER INSERT ON t1 FOR EACH ROWINSERT INTO t2 (dml_type, id, hoge)VALUES (1, NEW.id, NEW.hoge);o t1 テーブルへの insert 後に起動o NEW 変数で t1 テーブルへの insert 後の値を参照o t2 テーブルへ dml_type, id, hoge を insert
SQL解説 ~ トリガ AFTER DELETE
• CREATE TRIGGER delete_triggerAFTER DELETE ON t1 FOR EACH ROWINSERT INTO t2 (dml_type, id)VALUES (2, OLD.id);o t1 テーブルへの delete 後に起動o OLD 変数で t1 テーブルへの delete 前の値を参照o t2 テーブルへ dml_type, id を insert
SQL解説 ~ トリガ AFTER UPDATE
• CREATE TRIGGER update_triggerAFTER UPDATE ON t1 FOR EACH ROW IF (NEW.id=OLD.id) THENINSERT INTO t2 (dml_type, id, hoge)VALUES (3, NEW.id, NEW.hoge);
ELSEINSERT INTO t2 (dml_type, id, hoge)VALUES (2, OLD.id, OLD.hoge),
(1, NEW.id, NEW.hoge);END IFo t1テーブルへの update 後に起動o NEW.id=OLD.id なら t2 テーブルへ 1件 inserto NEW.id!=OLD.id ならt2 テーブルへ 2件 insert
SQL解説 ~ ファイル出力
• SELECT id, dml_type FROM t1 ORDER BY idINTO OUTFILE '/var/lib/mysql/test/t1_file';o テーブルデータをファイル出力する。
SQL解説 ~ ファイル入力
• LOAD DATA INFILE '/var/lib/mysql/test/t1_file'INTO TABLE t1 (id, dml_type);o 出力したファイルをテーブルに読み込む。
SQL解説 ~ テンポラリテーブル
• CREATE TEMPORARY TABLE t1 (id int, dml_type int);o セッション内のメモリ上に一時テーブルを作成o 他のセッションからは見えない。o メモリ上にあるので早い
• DROP TEMPORARY TABLE t1;o 一時テーブルを削除
SQL解説 ~ ユーザ定義変数
• SELECT @range_end := id, hoge FROM t1ORDER BY id LIMIT 100;o @range_end -> 100
• SELECT @range_end INTO @range_start;o @range_end -> 100, @range_start -> 100
• SELECT @range_end := id, hoge FROM t1WHERE (id > @range_start)ORDER BY id LIMIT 100;o @range_end -> 200, @range_start -> 100
• SELECT @range_end INTO @range_start; o @range_end -> 200, @range_start -> 200
• 「:=」を使うと参照と同時にユーザ定義変数を更新
SQL解説 ~ テーブルデータコピー
• INSERT INTO t2 (id, dml_type)SELECT id, dml_type FROM t1;o t1テーブルのデータを t2 テーブルに insert
SQL解説 ~ リネームテーブル
• RENAME TABLE old TO tmp, new to old;o old テーブルを new テーブルに置き換える。o ロックされているテーブルがあると実行できないo アクティブなトランザクションがあると実行できないo 名前の変更途中でエラーになるとロールバックする
稼働実績
• なしw• (手元で試した限りではまともに動いてます)
今後の課題
• 使い方が面倒(スクリプト化)• 実行時オプション指定ができるようにする
o Lock指定やログ出力など• lock table しなくてもいい方法を考える
免責事項
• 本プログラムの使用は各個人の責任において使用してください。
• 万が一、サービス上のデータ等が消滅・改ざんされたとしても当方は一切の責任を負いません。
募集
• 一緒に開発してくれる方、募集してます。https://github.com/nhayashi/p5-mysql-changeschema
謝辞
ご清聴ありがとうございました m(_ _)m