arel-mysql-index-hintとpt-online-schema-changeでのオプティマイズについて

arel-mysql-index-hintというgemをリリースしました。

MySQL on Rails/ArelでIndex Hintを付けまくるためのgemです。

Article.hint(force: :idx_article)
# => "SELECT `articles`.* FROM `articles` force INDEX (idx_article)"

Article.joins(:comments).hint(articles: {use: :idx_article})
# => "SELECT `articles`.* FROM `articles` use INDEX (idx_article) INNER JOIN `comments` ON `comments`

Article.joins(:comments).hint(comments: {force: :idx_comment})
# => "SELECT `articles`.* FROM `articles` INNER JOIN `comments` force INDEX (idx_comment) ON `comments"

すでにactiverecord-mysql-index-hintというgemがあるんですが、INNER JOINの右側にあるテーブルにIndex Hintを付けられないので、作った感じです。

pt-online-schema-changeでのオプティマイズ

まあIndex Hintを付けるのは良くないですよね。本来的にはDBの実行計画に従うべきです。 が、まあ使わざるをえない状況があるわけで…

とはいえ、統計情報がぶっ壊れているテーブルは直した方がいいですね。 CardinalityanullなテーブルはとっととOPTIMIZE TABLEした方がいいのですが、でっかいテーブルだと、気軽にOPTIMIZE TABLEを実行できません。

そこで我らがpt-online-schema-changeの出番です。マニュアルにもOPTIMIZE TABLEできる旨が書いてます。

http://www.percona.com/doc/percona-toolkit/2.1/pt-online-schema-change.html

Change sakila.actor to InnoDB, effectively performing OPTIMIZE TABLE in a non-blocking fashion because it is already an InnoDB table:

pt-online-schema-change --alter "ENGINE=InnoDB" D=sakila,t=actor

んが、MyISAMだとそうは問屋が卸さない。 http://dba.stackexchange.com/questions/44706/optimizing-disk-space-for-myisam-tables-what-is-the-benefit-of-alter-and-analyz

リンク先と検証した感じ、MyISAMだとALTER TABLEに加えてANALYZE TABLEを実行しないと、OPTIMIZE TABLEの代替にはならない… どうしたものかと思っていたら、pt-online-schema-change-analyzeというプラグインがありました。

pt-online-schema-change--pluginオプションなんてはじめて知ったよ!

ということで、上記のpluginを使うことでMyISAMでも無事オンライン最適化できました。万歳

pt-online-schema-change \
  --alter "ENGINE=MyISAM" \
  --host localhost \
  -u root \
  D=main,t=any_table,p="$PASSWD" \
  --charset=utf8 \
  --recurse=0 \
  --recursion-method=none \
  --max-load Threads_running=100 \
  --critical-load Threads_running=120 \
  --plugin /path/to/plugin/pt-online-schema-change-analyze.pl \
  --execute