SQL文実行の高速化

WHEREの左辺で算術演算子や関数を使わない

WHERE句の左辺に算術演算や関数を指定すると,インデックスが使われない。例えば,

SELECT NAME FROM CUSTOMERS
WHERE SAL - TAX > 1000

とすると,たとえSALフィールドにインデックスが定義されていてもテーブル全体を走査してしまう。こうした場合は,

SELECT NAME FROM CUSTOMERS
WHERE SAL > TAX + 1000

のように記述すれば良い。

「後方一致」検索はなるべく避ける

インデックスが付加されているフィールドであっても,LIKE '%AAA' のような「後方一致」を指定すると,インデックスを検索せずにデータ部の全表走査が行われる。したがって「後方一致」の使用はなるべく避けるようにする。どうしても必要であるなら,

・何らかの,少量まで絞り込める条件とAND条件で組み合わせる
・複数のフィールドに分割し,少しでも前方・完全一致できる範囲を広げる

といった方法を検討する。

IS NULL,IS NOT NULLを単独で使わない

条件を表すWHERE句にIS NULL/IS NOT NULLを指定したときは,インデックスを定義したフィールドであっても,全表走査が行われる。したがって,これらの条件を指定するときは,単独で指定するのではなく,何らかのかなり絞り込める条件を合わせて指定する。例えば,問い合わせの結果を変更せずに「B = 10」の条件を付加できるなら

WHERE A IS NULL

とする代わりに

WHERE A IS NULL AND B = 10

とする。

SELECT文で「*」を使わない

レコード長が長いときや,フィールド数が多いときには,すべてのフィールドを表す「*」を指定するのはできるだけ避けて,使用するフィールドだけを指定するようにする。「*」を指定すると,参照系のSQL文では,すべてのフィールドを繰り返してコピーするため,リソースを無駄に使うことになる。最低限度必要なフィールドだけを指定するのが基本である。

ORはある程度絞り込んでから使う

論理演算子ORを使用した場合,一応インデックスが使用されるものの,個々の条件が抽出する件数が少ない(数%程度)状態でないと,あまり効果がない。

DISTINCTの代りにEXISTSを使う

SELECT文にDISTINCT*Aを指定すると処理に非常に時間がかかる。DISTINCTを使用するのは極力避けるようにする。DISTINCTと同等の結果を得ることのできるSQL文にEXISTSがある。例えば,

SELECT DISTINCT a.ID1, a.NAME1 FROM
TABLE1 a, TABLE2 b WHERE a.ID1 = b.ID2

SQL文は,副問い合わせの条件としてEXISTSを指定して

SELECT a.ID1, a.NAME1 FROM TABLE1 a
WHERE EXISTS ( SELECT 'X' FROM 
TABLE2 b WHERE a.ID1 = b.ID2)

と書き換えることができる。同様に,NOT INからNOT EXISTSに代替することによってパフォーマンスが向上することもある。

GROUP BY,ORDER BY,HAVINGは注意する

GROUP BY句,ORDER BY句,HAVING句は,余分なディスク入出力が発生したりディスク領域を使うので,自分もしくはほかのプログラムのパフォーマンスに悪影響を及ぼしかねない。このことを念頭において,使わずに済むならなるべく使わないようにする。

演算子の組み合わせで速度が変わる

検索条件に,「>」「<」「=」をANDで組み合わせるときは,指定の仕方によってインデックスの使われ方が異なる。等号と不等号の組み合わせは,等号のみインデックスが使われる。例えば,

SELECT NAME FROM CUSTOMERS
WHERE JOB = 'MANAGER'
AND SAL > 1000

とすると,「JOB = 'MANAGER'」にはインデックスが使われるが,「SAL > 1000」には使われない。また,不等号同士の組み合わせでは,先に指定した条件だけにインデックスが使われる。つまり

SELECT NAME FROM CUSTOMERS
WHERE TAX > 100
AND SAL > 1000

SQL文では,RDBMSは「TAX > 100」だけにインデックスを使い「SAL > 1000」には使わない。

テーブルの別名を利用する

テーブルに別名をつけて,フィールド名にはその別名をつけると,SQL文の解析処理を減らすことができる。例えば,

SELECT ID, NAME FROM CUSTOMERS
WHERE SAL < 1000

よりも,

SELECT a.ID, a.NAME FROM CUSTOMERS a
WHERE SAL < 1000

のほうが高速になる。

SQL文の表現を統一する

本文中で述べたように,RDBMSは実行計画をキャッシュに保存しておいて再利用する。ところが,SQL文に定数を直接記述してしまうと,RDBMSは定数値だけが異なるSQL文を別のものと解釈するため,再利用されない。バインド変数を使用して,できる限りSQL文を統一するようにする。また,文字の大小や記述の仕方なども統一しておかないと別のSQL文だと認識されてしまうので,気を付ける。

SQL文を簡潔に記述する

SQL文はなるべく簡潔に記述するようにする。そうすることで,SQL文の処理時間を短縮することができる。