MySQLでBLOB/TEXT型カラムにインデックスを張る

/ db

MySQL で新たにテーブルを作ったり、プライマリキー、ユニーク制約、またはインデックスを作成する際、下記のようなエラーが発生することがあります。

ERROR 1170 (42000): BLOB/TEXT column 'text_field' used in key specification without a key length 

結論として回避策から書くと、BLOB型またはTEXT型の場合は、インデックス作成時にキー長を明示してあげる必要があります。

create index new_index on table_name(text_field(100));

このエラーは、MySQL が BLOB型もしくはTEXT型 (これらに順ずる TINYTEXT型 や LONGTEXT型を含む)のような可変長カラムでは、その先頭から最大255文字分しかインデックスできないという制約から来ているようです。解決策は上記のとおり、キー長を明示するか、変わりに255以下で VARCHAR(100) のようなカラムを使って、そちらをインデックスとして使うといった工夫が考えられます。

考えてみれば当然と言える話ではあります。

題目を索引することはあれど、本文を索引した書籍など見たことがないですし、そこに意味がないことは誰もが分かるでしょう。たとえ本文を索引にするとしても、冒頭の一節というのが関の山。この MySQL の仕様は、理に適っている気がします。逆に本文を索引したい、つまり全文検索用の FULLTEXT インデックスであれば、TEXT型カラムにもちろん作成することができます。

このエラーに遭遇したときは、上記のような解決法もひとつの手ではありますが、そもそも TEXT型カラムを主キーにしたり、インデックスを張ろうという設計が正しいかどうかを考えてみた方が良いでしょう。

例外は、百人一首的に冒頭の一節から引きたいか、50音順インデックスを使うようなケースだけじゃないでしょうか。LIKE 検索で、先頭数文字で引っかけたい場合。それも、通常は最低1000 レコードを超えてこないとインデックスが効いてこなかったりするので、さらにレアケースな気がします。

エラーが起きるとついつい今すぐで回避方法を探してしまいがちですが、そもそもエラーになるような設計が正しいかどうか考えるクセは付けておきたいもんです。結局、そういう考え方が未来の自分を救ったりするんだから。


このエントリーのトラックバックURL
http://www.deftrash.com/admin/mt4/mt-tb.cgi/521
とおりすがり at 2010年2月25日 14:14

たとえば顧客情報を電話番号をキーに管理するのが正しい設計ではないとでも?

dT at 2010年2月26日 01:19

携帯販売店のDBとかを想定して回答しますが、それは正しい設計だと思いますよ。
なぜなら、電話番号は可変長で持つとしても数百文字の任意文字列にはならないから。

このエントリで私が言いたかったのは、全文検索用のインデックスでもなく、
何百、何千文字というテキストを想定して、そこにインデックスを作成するのは無いよねーという話。

…ということを分かっていながら、敢えて質問するのはズルイっす。