MySQLをOPTIMIZEしてフラグメント化を解消する

ついさっきWordPressでリビジョンを無効化する件について書きました。
WordPressのリビジョン管理を無効化して不要なデータを削除 | 曖昧/旬.
そして大量のリビジョン情報を削除しました。

そうなると気になるのがMySQLデータベースのフラグメント化です。

フラグメント化って何かというと、歯抜けです。ぴっちり並んでいれば効率がいいのに、間開けて並んじゃっているから効率が悪くなっている状態です。

データベースでフラグメント化がいつ発生するかというと、主に行の削除です。行の削除は例えるなら、びっしり書かれた大学ノートのある1行を横線引いてなかったコトにしているようなものです。物理的には行が残っているのです。削除がどんどん走ると横線だらけになって生きたデータはほとんど残っていないかもしれません。

データベースがそんな状態だと、せっかく要らないデータを消したのに、効率は大して変わっていないかもしれません。それを解消する方法はデータベースによって異なります。MySQLなら OPTIMIZE TABLE というコマンドがあります。こいつはデータの最適化をしてくれます。PostgreSQLだと VACUUM FULL ですね。例えるなら、新しいノートに順序良く書き写して古いノートを捨てる処理です。

さて、まずMySQLはどの程度フラグメント化しているのでしょう。とりあえず SHOW TABLE STATUS で見てみます。記事を格納したテーブルにクローズアップ。

mysql> SHOW TABLE STATUS LIKE 'wp_posts';

出力は長すぎるので省略。重要なところは Data_length がテーブルのデータサイズで、Data_free が歯抜けの総量、ついでに Index_length がインデックスのサイズですね。この辺りの数値が OPTIMIZE でどう変化するか。OPTIMIZE します。

mysql> OPTIMIZE TABLE wp_posts;

完了。うちはデータ1,000件ほどですが、ほぼ一瞬でした。よっぽどじゃないと待つことにはならないでしょうね。そして数値を確認。Data_free が0になって、減った分 Data_length が小さくなっているはずです。ついでに Index_length も多少短くなっているはず。

というわけで、せっかくリビジョンの件から発展させているので、リビジョンデータを削除する前からの変化を見てみましょう。

タイミング Data_length Data_free Index_length
削除前 4466256 2704 258048
削除後 4466256 2264980 261120
OPTIMIZE TABLE後 2200740 0 208896

分かりやすいですね。データを削除すると歯抜けが発生して、最適化すると歯抜けがなくなってデータ長が短くなる。削除後のデータ長から歯抜け分を引くと2201276なので OPTIMIZE TABLE 後のデータ長とほぼ合います。若干ずれるのはテーブル構造の問題でしょう。

これで多少は効率化するでしょうか。ギリギリの運用ではないので差は出ないと思いますが、後でCPU使用率でも見てみるかな。アクセス数にもよるから一概に言えないんだけどね。

ちなみに OPTIMIZE TABLE する時はテーブル名をカンマで区切れば複数指定することができます。でも、ちょっと面倒。そんな人には wp-cli です。既にインストールしていたら、これを打つだけ。

$ wp db optimize

素晴らしい。しかし意図しているのかは分からないが、WordPressとは関係のないテーブルも OPTIMIZE してくれる。うちんとこは別にいいんだけど、OPTIMIZE 中はテーブルがロックされちゃうので余計なお世話なとこもありそう。

そして、この OPTIMIZE TABLE、あまり頻繁に実施する必要はないそうです。

可変長行の更新を頻繁にするとしても、特定のテーブルに対してだけ、この作業を週に一度、または月に一度以上する必要はありません。
情報源: MySQL :: MySQL 5.1 リファレンスマニュアル (オンラインヘルプ) :: 8.5.2.5 OPTIMIZE TABLE 構文.

まー、やっても悪くはならないだろうけど。