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の実行計画に従うべきです。 が、まあ使わざるをえない状況があるわけで…
とはいえ、統計情報がぶっ壊れているテーブルは直した方がいいですね。
Cardinalitya
がnull
なテーブルはとっとと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