uokadaの見逃し三振は嫌いです

ここで述べられていることは私の個人的な意見に基づくものであり、私が所属する組織には一切の関係はありません。

pt-online-schema-changeを試してみた。

pt-online-schema-change というPerconaが出しているテーブルのスキーマ変更ツールを試してみた。
普通に ALTER TABLE を実行すると実行中はテーブルロックが発生して書き込みが出来なくなるので
ブログのような書き込みがあるサービスの場合メンテナンス状態にする必要がある。

それがこのツールを使うとメンテナンス状態にしなくてもALTER TABLE出来るようになります。

percona-toolkit自体はmaatkitの後継にあたるツールなのでmaatkitでググればいくつか情報が集まるのでその辺読んでみて下さい。

とりあえず、percona-toolkitをインストール。

% sudo yum  install percona-toolkit
% /usr/bin/pt-online-schema-change 
  --alter 'ENGINE=InnoDB' # => ALTER TABLE テーブル名 以降のクエリを記述。
  D=foo,t=tweet,h=localhost,u=root  # => D=<データベース>,t=<テーブル>,h=<ホスト>,u=<ユーザー>
  --ask-pass  # => パスワードを渡すためのオプション
  --dry-run or --execute # => ドライランまたはALTER TABLE実行を選択するオプション。

ドライラン機能もあるので勝手にALTER TABLEが実行されることも無くて安心。

% /usr/bin/pt-online-schema-change --alter 'ENGINE=InnoDB' D=foo,t=tweet,h=localhost,u=root --check-plan --ask-pass  --dry-run
Enter MySQL password: 
Starting a dry run.  `foo`.`tweet` will not be altered.  Specify --execute instead of --dry-run to alter the table.
Creating new table...
Created new table foo._tweet_new OK.
Altering new table...
Altered `foo`.`_tweet_new` OK.
Not creating triggers because this is a dry run.
Not copying rows because this is a dry run.
Not swapping tables because this is a dry run.
Not dropping old table because this is a dry run.
Not dropping triggers because this is a dry run.
Dropping new table...
Dropped new table OK.
Dry run complete.  `foo`.`tweet` was not altered.

今回は下のtweetテーブルに更新時間を記録するカラムを追加してみます。

CREATE TABLE IF NOT EXISTS tweet (
    tid  INT(10)       AUTO_INCREMENT,
    body VARCHAR(255),
    PRIMARY KEY (tid)
)Engine=InnoDB DEFAULT CHARSET=utf8;

こんな感じでオプションを設定してコマンドを実行する。

% /usr/bin/pt-online-schema-change --alter 'ADD update_time TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP' D=foo,t=tweet,h=localhost,u=root --ask-pass  --execute 
Enter MySQL password: 
Altering `foo`.`tweet`...
Creating new table...
Created new table foo._tweet_new OK.
Altering new table...
Altered `foo`.`_tweet_new` OK.
Creating triggers...
Created triggers OK.
Copying approximately 1 rows...
Copied rows OK.
Swapping tables...
Swapped original and new tables OK.
Dropping old table...
Dropped old table `foo`.`_tweet_old` OK.
Dropping triggers...
Dropped triggers OK.
Successfully altered `foo`.`tweet`.

MySQLにアクセスしてテーブルを確認します。

mysql> show create table tweet \G
*************************** 1. row ***************************
       Table: tweet
Create Table: CREATE TABLE `tweet` (
  `tid` int(10) NOT NULL AUTO_INCREMENT,
  `body` varchar(255) DEFAULT NULL,
  `update_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`tid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.01 sec)

見事、update_timeが追加されてますね。


まとめ、なんとなく使ってみたけど不可解な挙動がまだまだあるのでもう少し調査が必要かなって印象。
ただ、実行中は書き込みのパフォーマンスが落ちるのでパフォーマンス要求がキツイサービスの場合は使えないかも。