SQLの解析を少なくする
共有プールにキャッシュされた情報は、SQLが完全に同一の場合にのみ再利用されます。WHERE句に指定されている条件値が異なっている場合、もしくはSQLの意味が同一でもスペースの個数、改行位置、大文字、小文字など、少しでも異なっている場合には、違うSQLとして新たに解析されます。下表にSQLが共有されない例を示します。
実行されたSQL文 | 共有されない理由 |
SELECT * FROM emp WHERE empno=7788; | インスタンス起動後や、共有プールのフラッシュ後、初めて実行する場合は必ずSQLの解析が発生する |
SELECT * FROM emp WHERE empno=8000; | WHERE句に指定されている条件値が異なる |
SELECT * FROM emp WHERE empno=7788; | スペースの個数が異なる |
SELECT * FROM EMP WHERE empno=7788; | 大文字、小文字が異なる |
上記のSQLはすべて違うSQLとして解析されます。どのような場合にSQLの解析が発生するのかを理解し、SQLの解析の発生を少なくすることを意識してください。解析済みのSQLを共有し、パフォーマンスを上げるには、次のような方法があります。
バインド変数の利用
WHERE句に指定されている条件値が異なるため共有されない問題に関しては、パラメータ変数を使用することにより解決できます。パラメータ変数は、OracleParameter
クラスを利用します。Where句に指定されている条件を次のようにハードコーディングすることなくパラメータ変数を使用することにより、SQLの解析をなくし、パフォーマンスを向上させることが可能です。
Dim cmd As New OracleCommand( _ "SELECT * FROM emp WHERE empno=:pEmpNo", conn) Dim pEmpNo As OracleParameter = _ cmd.Parameters.Add("pEmpNo", _ OracleDbType.Int32, ParameterDirection.Input) pEmpNo.Value = 7369
OracleCommand cmd = new OracleCommand( "SELECT * FROM emp WHERE empno=:pEmpNo", conn); OracleParameter pEmpNo = cmd.Parameters.Add("pEmpNo", OracleDbType.Int32, ParameterDirection.Input); pEmpNo.Value = 7369;
しかし、ソースコードを変更するのが難しい場合には、Oracleの共有カーソル機能を使用することで、類似したSQLを内部的にバインド変数化し、解析結果を共有させることができます。共有カーソル機能を使用するためには、初期化パラメータ「CURSOR_SHARING」を設定します。設定可能な値と機能は次のとおりです。
設定値 | 説明 |
FORCE | リテラルがわずかに異なっても、同一のSQLとして共有します。 |
SIMILAR | 実行計画が同一であれば、同一のSQLとして共有します。 |
EXACT | 完全に同一のテキストを含むSQLのみ共有します(デフォルト値)。 |
動的SQLを多用している場合、SIMILARやFORCEを指定するとパフォーマンスが向上する可能性があります。ただし、FORCEを指定した場合は実行計画次第でパフォーマンスが落ちる場合もありますので、パラメータを変更する前に十分にテストを行ってください。
今まで説明したような、パラメータ変数を利用する方法と初期化パラメータ「CURSOR_SHARING」を設定する方法以外にも、ステートメント・キャッシングという機能を利用してSQLの再解析を防ぐことが可能です。
ステートメント・キャッシング
ステートメント・キャッシュを利用することにより、同じSQL文を(場合によっては異なるパラメータ値を使用して)後で実行する場合、カーソルから解析された情報を再利用して、文を解析せずに実行することで、パフォーマンスを向上させることが可能です。
ステートメント・キャッシュを利用するには、接続文字列属性で「Statement Cache Size」を指定します。この属性は、ODP.NETステートメント・キャッシュを有効化または無効化します。デフォルトでは、この属性は0に設定され、ODP.NETステートメント・キャッシュは無効です。0より大きい値に設定することで、ODP.NETステートメント・キャッシュが有効になり、指定された値は、接続用にキャッシュできる文の最大数として使用されます。指定された最大キャッシュ・サイズまで接続がキャッシュされると、最低使用頻度のカーソルが解放され、新しく作成されたカーソルをキャッシュするためのスペースが確保されます。ステートメント・キャッシュの利用は、次のようにOracleへ接続するための接続文字列、「Statement Cache Size」に接続用にキャッシュできる文の最大数を指定します。
"User Id=SCOTT;Password=TIGER;Data Source=ORCL;Statement Cache Size=100"
ステートメント・キャッシュ利用時も、「SQLの解析を少なくする」で説明した時と同様に、パラメータ変数を使用しないと、別のSQLとして解析が行われてしまいますので、ステートメント・キャッシュ利用時は必ずパラメータ変数を使用してください。
おわりに
ODP.NETにはデータベースへのアクセス速度を向上させるプロパティ、メソッドが多数用意されており、開発者はこれらの機能を上手に活用すれば、ハイパフォーマンスなデータベースアプリケーションを開発できます。次回も引き続きパフォーマンスを向上させるための様々な手法を説明しますので、ご期待ください!