MySQLでALTER TABLE文の進捗状況を確認する

MySQLでテーブルへのカラム追加やテーブルの再編成を行うには、ALTER TABLE文を使用します。MySQLのALTER TABLE文は、変更後の定義にもとづく作業用テーブルを作成し、変更前のテーブルから作業用テーブルへデータをコピーして、最後に二つのテーブルを入れ替えるという仕組みになっています。テーブルへのインデックス追加についても、現在のところ大半のケースで内部的にALTER TABLE文が実行されています。
ALTER TABLE文の怖いところは、処理がもうすぐ終わるのかどうかが分からないところです。テーブルサイズが1GBを超えるあたりから分単位の時間がかかるようになり、100GBともなると本当に終わるのか?と見ていて不安になります。メンテナンス時間が限られている場合は、作業を中断すべきかどうか難しい判断を迫られることもあります。
実は、というほどではありませんが、ALTER TABLE文の進み具合を確認する方法があります。

mysql> SHOW GLOBAL STATUS LIKE 'Handler_write';
+---------------+----------+
| Variable_name | Value    |
+---------------+----------+
| Handler_write | 22472949 |
+---------------+----------+
1 row in set (0.00 sec)

ALTER TABLE文は内部的に作業用テーブルへのINSERT処理を実行するので、ステータス変数Handler_writeにINSERTされたレコード件数が記録されていきます。

mysql> ALTER TABLE order_line ENGINE = InnoDB;
Query OK, 4796697 rows affected (1 min 4.78 sec)
Records: 4796697  Duplicates: 0  Warnings: 0

mysql> SHOW GLOBAL STATUS LIKE 'Handler_write';
+---------------+----------+
| Variable_name | Value    |
+---------------+----------+
| Handler_write | 27269647 |
+---------------+----------+
1 row in set (0.00 sec)

ですから、作業開始前にHandler_writeの値と対象テーブルのレコード件数を控えておけば、どこまで処理が進んだのかを確認することができるのです。InnoDBの場合はInnodb_rows_insertedでも同じ値が取れます。

#!/bin/bash

while true
do
  cat <<_EOF_
SHOW GLOBAL STATUS LIKE 'Handler_write';
_EOF_
  sleep 10
done | mysql -u root -p -N
$ ./watch.sh
Enter password:
Handler_write   27270904
Handler_write   27270916
Handler_write   27270917
Handler_write   27270918
Handler_write   27981431
Handler_write   28791103
Handler_write   29546564
Handler_write   30319521
Handler_write   30980129
Handler_write   31629177
Handler_write   32067622
Handler_write   32067623
Handler_write   32067624
Handler_write   32067625
Handler_write   32067626

ただしテーブルサイズが大きくなるとINSERT処理がだんだん遅くなるため、最初の10分間で1億レコード処理できたとしても、次の10分間でまた1億レコード処理できるとは限らないという点には注意が必要です。