MS SQL には照合順序というものがあります。英語で言うと COLLATION でしょうか。
手っ取り早く言うと文字の大小比較に使う設定で、例えば CS (Case Sensitive)だと大文字小文字を区別するし、CI(Case Ignore)だと区別しません。
MS SQLの照合順序は日本語だけでもかなりの数があるので、最初はちょっと混乱します。
若干複雑なところもありますが、使えるようになるととても便利なので、私は COLLATE とか結構多用していました。
インスタンス、データベース、テーブル、カラム、クエリそれぞれの単位で設定できるでとても便利。
大文字小文字やひらがなカタカナを区別しないLike検索とかソートとかって結構要求されることが多いし、これをアプリケーション側でちまちま実装するよりかは早くて簡単ですから。
ただし比較対照のカラムの照合順序があってないとエラーが発生するので、意味が分かっていない当時は結構苦慮していましたけれども。
一時テーブルの照合順序は確かインストール時の照合順序か何かがデフォルトになるので、一時テーブルと結合するときには注意が必要だったりとかもあったような。
ちゃんと触ったことはないけど、MySQLにも数は少ないながら照合順序の仕組みはちゃんとあって、テーブルやカラム単位での指定もできるし、COLLATE でクエリ単位で使うことも出来たと思います。
で、Oracle。
大文字小文字やひらがなカタカナを区別しないLike検索と、辞書順ソートの要求はやっぱりあったので、MS SQLと同じノリで照合順序で対応しようとしました。
が・・・。
なんか仕組みが違います。
Oracleには NLS という多言語対応の仕組みが合って、照合順序に相当するものは NLS_SORT とNLS_COMP のようです。
照合順序とはちょっと違うので、言語ソートとか呼んでいるみたい。
基本的に環境変数で設定を行う Oracle のやり方には混乱しっぱなしですが、これらの設定は インスタンス(≒データベース)、セッション単位で設定を行うことが出来ます。
テーブルやカラム単位では設定することはできないようです。
(権限があれば)必要とするクエリの直前に ALTER SESSION を発行してまた元に戻せばいいので、クエリ単位でできる、といえないこともないです。
COLLATE はどうやらありません。
NLSSORT 関数というものはあるので、単純な比較や order by だけであれば、クエリの内部で照合順序を使うようなことは可能です。
が、これは % や _ などのメタ文字との組み合わせがほぼ必須となる、like 検索では使用できないようです。
はて、と困りました。
「よーしパパ照合順序で対応しちゃうぞ~~!」と意気込んでみたら、なんか事情が違います。
生クエリをゴリゴリ書いたりできるプロジェクトであれば、 ALTER SESSION と NLSSORT 関数を使いまわしてなんとかできそうなんですが、今のプロジェクトでは O/Rマッパーである Hibernate を使っており、基本的に SQL は自動生成です。
特定のクエリ発行時だけ ALTER SESSION を発行するメソッドを呼び出すようにするとかなんとか考えたりもしたんですが、当時はある程度固まったDAO の使い方のルールに例外的措置を加えることになってしまうので、それもどうかという話になり。
あれこれ考えた末、結果的にはログイントリガで ALTER SESSION を発行することで対応しました。
NLS_SORT に JAPANESE_M_CI、NLS_COMP に LINGUISTIC を設定しています。
なんか CLOB なカラムには見事に効いていないようですが・・・(Oracle Textとか使わないとなのかしらん)。
しかしプロジェクト終盤に入った今は、このやり方は失敗だったのかなあと思っています。
当然すべての文字列型の比較やソートでこの NLS_SORT と NLS_COMP の設定が有効になるわけで、辞書順ソートや比較が必要のないケースではパフォーマンス上の問題が発生します。
というか、実際に発生したんですね。
CHAR型だけど値の中身は全部数値になってるカラムを IN 句で1000件条件指定して UPDATE するクエリを実行したら、10分以上ダンマリって結果が・・・。
2万件の UPDATE を1000件ずつ実行してるんですが、1時間たっても終わらないのでブラウザがタイムアウトとか阿保みたいな状態になってしまいました。
Oracleを扱う上でとても参考させていただいている Shift-The-Oracle さんも以下のように警告しています。
また NLS_COMP と NLS_SORT の NLS パラメータ を設定することによってオプティマイザによるアクセスパスがパフォーマンスに影響が出るくらいに大きく変化することにも注意を払う必要がある。
全角・半角、大文字・小文字を区別しない検索
文字列型カラムを大量に指定しない限りそこまで影響が出たりはしないのか、ログイントリガを設定した当初はあれこれ心配したものの特に遅くなったりもしなかったので、大丈夫かなと踏んでいたんですが。
世のOracle使いの方々は、「大文字小文字やひらがなカタカナを区別しないLike検索」の際には、どうやっているんでしょうか?