かみぽわーる

kamipo's blog

MySQL(InnoDB) で "Index column size too large. The maximum column size is 767 bytes." いわれるときの対策

tl;dr: MySQL 5.5.14以降だとinnodb_large_prefixオプションで3072バイトまでインデックス張れる

MySQL(InnoDB)では、ひとつのカラムのキープレフィックスの最大値が767バイトという制限があるので、ついうっかりして

Index column size too large. The maximum column size is 767 bytes.

とか

Specified key was too long; max key length is 767 bytes

といったエラーを見たことある人は多いのではないかと思います。

よくあるケースだと、varchar(256)以上のutf8なカラムにインデックスを張ろうとするとこのエラーとご対面できます。

CREATE TABLE t (c varchar(256), index (c));
ERROR 1709 (HY000): Index column size too large. The maximum column size is 767 bytes.

で、話は変わってもうMySQL 5.5 GAが出てから一年が経ち、MySQL 5.6 GAもそろそろ出るころだし、新規で作るアプリケーションはutf8mb4でいきたいわけじゃないですか。

そこで、Rails(ActiveRecord)をutf8mb4で動かしたいわけなんですが、db:migrateするとしょっぱなからschema_migrationsってテーブルにインデックス張れなくて落ちます。

utf8のときのスキーマはこんなの。

CREATE TABLE `schema_migrations` (
  `version` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  UNIQUE KEY `unique_schema_migrations` (`version`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

ActiveRecordでstring型のカラムを定義すると、MySQLだとvarchar(255)になるので、utf8mb4だとインデックス張ると767バイトを超えてしまう。

で、なんかきれいに解決できる方法ないかなって考えたんだけど、MySQL 5.5.14以降だとinnodb_large_prefixというオプションが追加されてて、キープレフィックスの制限を3072バイトまで拡張できます。

ただし、ROW_FORMATをDYNAMICかCOMPRESSEDにする必要がある(デフォルトはCOMPACT)ので、ActiveRecordのcreate_tableメソッドをちょいと書き換えてデフォルトのROW_FORMATをDYNAMICにすればよさそうなんで、とりあえずそうしてます。

my.cnfに以下を追加して

[mysqld]
innodb_file_format = Barracuda
innodb_file_per_table = 1
innodb_large_prefix

最終的なスキーマはこんなかんじ。

CREATE TABLE `schema_migrations` (
  `version` varchar(255) NOT NULL,
  UNIQUE KEY `unique_schema_migrations` (`version`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC

参考

#isucon2 にて死す

当日を振り返った翌日の感想はコチラ。

今回もチームやすべえとして@くんに熱烈ラブコールを送ってたんですが、当日は飛行機の上ということで振られてしまったので、それぺちの@さんとRails高速化の@さんまったく接点のない二人を誘って参加しました!

二人とも突然の誘いを快く受けてくれてありがとうございました!!

結果はというと、まずクエリのボトルネックをインデックス張ってつぶしたあたりまではよかったんですが、サイドバーのキャッシュの不整合を解決できずDBから引き直そうとしたところで致命的な設計ミスに気づいてしまって、せめて完走させてスコアは出そうってことでgit initした状態に戻してフィニッシュでした。

個人的に力不足だったなと思うところが多くて、優勝したfujiwara組のレポートで、ボトルネックを着実に計測してそれに基づいて施策を打ち出していく、これがベーシックなようで本当にむずかしく、歴然とした実力の差があったんだなと感じました。あとはメンバーそれぞれの役割が分担されてることで、チームとしてより大きな成果につながったんだなというのも感じました。

こういうコンテストで人と競い合うことで、あらためて自分のスキルや他のエンジニアの人たちとの差がわかって、自分はどうなりたいのかとか何ができるようになりたいのかを考えるきっかけになってすごくよかったです。

あとはとにかく楽しかった!仕事でも発揮したことない今年一番の集中力を発揮した!

この気持ちをバネにして次はリベンジ果たしたいですね。

Linuxと挙動がちがってて使いにくいOS Xのコマンド(top/ps/netstat)の代替

GNU/Linuxに慣れてると、よく打つtop/ps/netstatOS X使ってるときにLinuxのそれと全然ちがう挙動で使いにくい。同じ挙動にするのman見ても無理そうなんで、なんとか同じように使えるのないか調べてみた。

top

htopならLinuxOS Xで同じように使えるのでhtopを使うとよさそう。

brew install htop-osx

ps

psのいい代替は見つからなかったけど、ps auxfのようにツリー表示したいときの代替はpstreeを使うとよさそう。

brew install pstree

netstat

netstatnetstat -tnpaとかnetstat -tnplをよく使うけど、前者はlsof -nP -iTCP、後者はlsof -nP -iTCP -sTCP:LISTENで代替できそう。

$ sudo lsof -nP -i4TCP -sTCP:LISTEN
COMMAND    PID   USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
launchd      1   root   28u  IPv4 0x848d6f3ed164cf3b      0t0  TCP 127.0.0.1:631 (LISTEN)
klnagent    74   root    7u  IPv4 0x848d6f3ed164c803      0t0  TCP 127.0.0.1:30523 (LISTEN)
klnagent    74   root    8u  IPv4 0x848d6f3ed164c0cb      0t0  TCP 127.0.0.1:49152 (LISTEN)
Dropbox    350 kamipo   19u  IPv4 0x848d6f3ed3807993      0t0  TCP *:17500 (LISTEN)
Dropbox    350 kamipo   25u  IPv4 0x848d6f3ed3804e43      0t0  TCP 127.0.0.1:26165 (LISTEN)
Growl     9088 kamipo    4u  IPv4 0x848d6f3ed864ef3b      0t0  TCP 127.0.0.1:23053 (LISTEN)
mysqld   81912 kamipo   27u  IPv4 0x848d6f3ed924ae43      0t0  TCP *:3306 (LISTEN)
Skype    91096 kamipo   39u  IPv4 0x848d6f3ed9844b23      0t0  TCP *:22493 (LISTEN)

おまけ

あとOS Xのtarはイケてないという噂をよく聞くのでGNU tarも入れておくとよいかもしれないですね。

brew install gnu-tar

YAPC::Asia 2012 に行ってきた

今年も行ってきました!

1日目はtokuhiromのToramotemenさんのWightのトークがおもしろかった。

2日目のPerl 今昔物語の対談で個人的に印象に残ったのが、nekokakさんの自分はサラリーマンプログラマだったけどいまこうやって登壇するようになったのはtokuhiromがきっかけだったみたいな話があって、僕もPerl Mongersの中で一番影響受けたのをだれかひとりを選べといわれたらtokuhiromのハックする姿勢をいつもかっこいいなーと思っていたからすごく共感した。

あとそんなtokuhiromも最初のYAPC::AsiaのLTではまわりがみんなおもしろくて緊張したという話をしていて感慨深かった。

僕がはじめてYAPC::AsiaでLTしたときも、直前のyusukebeさんのmiyagawanize LTがすごいおもしろくてあまりの緊張ですこしマイクがうわずったりもしたけど、そのあとの懇親会でtypesterさんに「ファンになりました」ってひろってもらえてすごくうれしかったのを思い出した。

そういう体験もあって、僕がトークを聞いておもしろかったと思ったら「おもしろかったよ!」って伝えるようにしていて、今年もそういう体験をした人がいたのかなーと思うとまた感慨深い。

これからも、そういう体験をできる場が続いていくといいなーと思いました。

MySQL Casual Talks Vol.3 でスベってきました

MySQL Casual Talks Vol.3 : ATND おつかれさまでした!

去る4月19日はこじはることAKB48小嶋陽菜の誕生日でした!

先日の握手会でそのことに気づいてしまったので
なにかこじはるネタでLTをしたいなということで
Haruna storage engineというネタをやりました。

AKBとmysql-buildの話

InnoDB Deep Talk #1 : ATNDd:id:moriyoshiさんがLTしていた
InnokoDBをパクったForkしただけのネタなんですけど

テーブル名で動作が変わるストレージエンジンネタもやってみたかったので
テーブル名に"mariko"が含まれてると麻里子様のツイートも取ってくるようにしてみました( *`ω´)八(бвб)

きもい、滑ってる、これはひどい、などの率直な感想を頂いておりますが
これに懲りずにまた呼んでください!よろしくおねがいします!!