インデックスの活用
今回はさらに高度なインデックスの活用について解説します。
複合インデックス
ここまでは単一の列に対して作成するインデックスを前提にお話ししてきました。 しかし、インデックスは同一テーブルの複数の列に対してまとめて設定することもできます。検索条件に複数列を指定する場合などは、このようなインデックス を使えばさらに効率よく処理を行うことができます。
SELECT * FROM t1 WHERE col1 = 1 AND col2 = 2;
たとえば上記のような検索において、次のように複合インデックスを作るとします。
CREATE INDEX col12index ON t1 (col1, col2);
すると、col12indexを参照するだけでWHERE句の条件を満たす行を一度に抽出できます。
なお、注意しておかなければならないのは、下記のようなOR条件検索では複合インデックスが有効にならず、col1とcol2の別々のインデックスが必要になることです。
SELECT * FROM t1 WHERE col1 = 1 OR col2 = 2;
ただし、「col1, col2」という複合インデックスはcol1の検索にも使えるので、「col1,col2」という複合インデックスに加え、col2のインデックスだけを新たに作ればよいということになります。
一般に「col1, col2, col3, … coln」という複合インデックスは、col1からm(m≦n)番目の列を連続してAND条件で結んだ検索条件に適用できます。たとえば、「col1, col2, col3」という複合インデックスは、次のケースに利用できます。
col1 = 1
col1 = 1 AND col2 = 2
col1 = 1 AND col2 = 2 AND col3 = 3
一方、次のようなケースには利用できません。
col2 = 1
col2 = 1 AND col3 = 2
col1 = 1 AND col3 = 2
式インデックスと関数インデックス
PostgreSQLでは、列の値を直接インデックス化するだけでなく、列の値をもとに計算した結果や、列の値を関数に渡した結果をインデックスにすることができます。このようなインデックスを式(expression)インデックスと呼びます。
SELECT * FROM t1 WHERE 'foo' || i = 'foobar';
たとえば上記のような検索を頻繁に行う場合、次のように式インデックスを作ります。二重かっこが必要なことに注意してください。
CREATE INDEX tifooindex ON t1 (('foo' || i));
式インデックスでは、同じテーブルの複数の列を使って計算した結果をインデックスにすることもできます。たとえば、i、jという列を持つテーブルt1で次のような検索が頻繁に行われる場合を考えてみます。
SELECT * FROM t1 WHERE i || j = 'ab';
このような場合は、次のように2つの列を使った式インデックスを作っておくと効果的です。
CREATE INDEX ijindex ON t1((i || j));
式インデックスの中でも関数を使ったものを関数インデックスと呼びます。たとえば、次のように大文字小文字を無視した検索を行うためにupper関数(小文字を大文字に変換する関数)を使う場合、iにインデックスが設定されていても利用されることはありません。
SELECT * FROM t1 WHERE upper(i) = 'FOO';
このようなケースでは、次のようにしてupper(i)の結果を関数インデックスにするのが効果的です。
CREATE INDEX t1upperindex ON t1(upper(i));
インデックスを使うことによって検索スピードが上がるだけでなく、実行時に関数を実行するオーバーヘッドがなくなります。
関数インデックスの対象となる関数は組み込み関数だけでなく自前の関数でもかまいませんが、関数の属性は必ず「IMMUTABLE」でなくてはなり ません。考えてみればこれは当然です。あらかじめ値を計算しておくことになるので、実行時の条件にかかわらず引数だけで結果が決まる関数でなければなりま せん。