sqlite の LIKE 演算でインデックスを使う方法
sqliteで、次の条件を満たしたselectでインデックスが使われていませんでした(explainで確認)。
- インデックスを張ったカラム
- LIKE '/foo/bar/%'のように%が最後
次のページにsqliteがLIKE演算子に対しインデックスを使う条件が書いてありました。
case-sensitive=OFFの時、sqliteは上記のようなLIKE演算に対して、インデックスを使ってくれません。
張ったインデックスの collating sequence は何でしょうか?どこでも何も指定しなければデフォルトの BINARY ですが、case-insensitive な演算に使うためには NOCASE でないといけません。
また、インデックスを使う条件に if case_sensitive_like mode is disabled then the column must use the built-in NOCASE collating sequence.
と書かれているように、その column も NOCASE でないといけません。つまり、次のようしないといけません。
CREATE TABLE t (c COLLATE NOCASE); CREATE INDEX t_c ON t (c COLLATE NOCASE); -- COLLATE NOCASE は省略可; SELECT * FROM t WHERE c COLLATE NOCASE LIKE 'hoge%'; -- COLLATE NOCASE は省略可;
あるいは、
CREATE TABLE t (c); CREATE INDEX t_c ON t (c COLLATE NOCASE); SELECT * FROM t WHERE c COLLATE NOCASE LIKE 'hoge%';
sqliteのデフォルトは、case-sensitiveがOFFです。つまり、文字列比較の時、大文字小文字を区別しません("abc"と"ABC"が等価になります)。多くの局面で、不当なデフォルト設定だと思いますが、SQL標準がそう要求しているようです。
SQLite のソースにはそういうコメントがあるのですが、それ以外ではそのような記述は、まず見かけませんよね。LIKE 演算についても、他の文字列比較と同様に、comparand の collating sequence によって case sensitive かどうか決まるのが正しいのではないかと思うのですが、標準がどうであれ、現状の SQLite を使う以上は現状の実装に従うしかないですね。
SQLite で case-insensitive なパターンマッチをしたい場合はPRAGMA case_sensitive_like
を使って case-insensitive にした上で LIKE 演算をする方法もありますが、これはコンパイル時に有効になっていなければ使えなかったりします。そんなときは、SQLite 独自の方法ですが、GLOB 演算を使う方法があります。これは常に case-sensitive です。ただ、LIKE 演算とはパターンの書き方が違っていて、% とか _ ではなく * とか ? を使います。
コメント
コメントの投稿
トラックバック
http://a8i.blog78.fc2.com/tb.php/34-29729fbe
この記事にトラックバックする(FC2ブログユーザー)