Sub::Throttle で MyISAM テーブルのホットメンテナンス

Kazuho@Cybozu Labs: 実行時間を抑制するモジュール Sub::Throttle を書いた の話。

サービスを動かしたまま、テーブルの全行書き換えをやりたいこととかって時々あるけど、MyISAM で単純に update ... とかやると、全行の更新が完了するまでの間テーブルがロックされちゃってサービスが停止状態になってしまう。回避方法としては、

% perl -le 'print "update ... where $_<=id and id<$_+10000;" for 0..10000' | mysql ...

とかみたくして、update 文を分割して流すんだけれども、それでもテーブルをロックする期間が長過ぎて、他のクエリが詰まってしまったりする。こういう場合に、

% perl -MSub::Throttle=throttle 'for ($id = 0; $id < 100000000; $id += 10000) { throttle(0.5, sub { system("echo \"update ... where $id<=id and id<$id+10000;\" | mysql ...") }) }'

とかみたく書くことで、テーブルロックする期間を 50% (=0.5) に抑えられる。という使い方を今、実践中。