SQLチューニング
【エンジニア募集中】フルリモート可◎、売上/従業員数9年連続UP、平均残業8時間、有給取得率90%、年休124日以上 etc. 詳細はこちらから>
SQLチューニングはSQLの実行で性能問題がある場合、SQLの内部処理を解析し、処理が遅いSQL文を対象に、最適化するプロセスです。このプロセスを繰り返して実施し、目標の性能に合うように行うのは一般的です。
SQLチューニングには、インデックスの存在はとても大きいです。
インデックス
インデックスとは、テーブルへの処理を高速化するためのデータ構造である。目的のレコードを効率よく取得するためのラベルのようなものです。
インデックスを作成することはよく“インデックスを貼る”と言われています。SQLの性能問題の8割はインデックスを貼ることで解決されると言われています。
INDEXの作成
INDEXの作成にはCREATE INDEX文を使用します。
CREATE INDEX スキーマ名.インデックス名 ON インデックスを作成するテーブル名(列名 [ASC | DESC], …
ですが、多くのプログラマーはこのような経験があるかと思います:インデックスを貼ったが、性能は全く改善されません。実行計画を確認すると、貼ったインデックスは使用されていません。
今回の記事では、インデックスが使用されないクエリの例を紹介します。
WHERE句がない
インデックスはWHERE句、ORDER BY句、またはGROUP BY句で指定されているカラムに貼るのは一般的です。WHERE句、ORDER BY句、またはGROUP BY句がない場合、インデックスが効かず、テーブルフルスキャンになります。
WHERE句などで主キーを指定する場合、DBの種類によって、インデックスをわざわざ貼る必要がない場合があります。Oracleデータベースの場合、テーブル作成時、主キーには自動的にインデックスを貼ってくれます。
IS NULLまたはIS NOT NULLを使用している
こちらもデータベースの種類によりますが、MySQL、SQL Server、PostgreSQLの場合、IS NULLまたは IS NOT NULLを使用する場合、インデックスが使用されます。Oracleの場合、IS NULLとIS NOT NULL式がある場合、インデックスが使用されません。
・インデックス列で演算をしている
下記のクエリはインデックスが使用されません(BIRTH列にはインデックスが貼られているものとする)
例:
SELECT * FROM T_STUDENTS WHERE TRUNC(BIRTH) = ’01-MAY-98’
この場合、下記のように右側に式を書き換えれば解決されます。
SELECT * FROM T_STUDENTS WHERE BIRTH < (TO_DATE ( ’01-MAY-98’ + 0.9999)
MAXとMIN関数を使用する場合、Oracleはインデックスを使用します。
LIKE %であいまい検索をしている
WHERE句に“等しくない”式を使用している
下記の式らを使用する場合、インデックスが無視されます。
<>、!=、NOT colum >=?、NOT colum <=?
こういう場合、インデックスを効かせるには、式の書き換えが必要です。
例えば、colum<>0はcolum>0 OR colum <0に書き換えれば、columに貼るインデックスが有効になります。
WHERE句に“=”と範囲判定式を同時に使用する
SELECT STUDENT_ID, STUDENT_NM
FROM T_STUDENT
WHERE KAKARI = ‘IKIMONO’ AND GRADE >2
KAKARIとGRADE列は単独インデックスの場合、Oracleは最初のほうだけを使用することになるため、GRADE列に貼るインデックスは無効になります。
WHERE句にデータ型を間違って使用している
STUDENT_IDはVARCHAR2型とする。このカラムにはインデックスが貼られているものとする。
SELECT * FROM T_STUDENT
WHERE STUDENT_ID = 801234
このクエリを実行する際、テーブルはフルスキャンされます。その理由は、Oracleは自動的にWHERE句を下記のように変換します。
SELECT * FROM T_STUDENT
WHERE TO_NUMBER(STUDENT_ID) = 801234
下記のように書き直せば、インデックスが有効になります。
SELECT * FROM T_STUDENT
WHERE STUDENT_ID = ‘801234’