Online schema change in mysql casual #1(2010/12/11)

1,573 views

Published on

0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,573
On SlideShare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
1
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide
  • MySQL::ChangeSchema で使っている SQL を抜粋して説明します。
  • Online schema change in mysql casual #1(2010/12/11)

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

    ×