Online schema change in mysql casual #1(2010/12/11)
-
Upload
naritoshi-hayashi -
Category
Documents
-
view
570 -
download
2
Transcript of Online schema change in mysql casual #1(2010/12/11)
問題点(サービス止めない場合)
• 気軽に ALTER 文を打つとテーブルロックがかかる• アプリ側の対応が必要で大変• どこまで更新処理をしたか既存データ移行後に全部追う必
要があり整合性の確認が大変
使い方
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
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_trigger AFTER INSERT ON t1 FOR EACH ROW INSERT 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_trigger AFTER DELETE ON t1 FOR EACH ROW INSERT 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_trigger AFTER UPDATE ON t1 FOR EACH ROW IF (NEW.id=OLD.id) THEN INSERT INTO t2 (dml_type, id, hoge) VALUES (3, NEW.id, NEW.hoge); ELSE INSERT INTO t2 (dml_type, id, hoge) VALUES (2, OLD.id, OLD.hoge), (1, NEW.id, NEW.hoge); END IF
o 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 id INTO 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 t1 ORDER 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 t1
WHERE (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 名前の変更途中でエラーになるとロールバックする