開発者:ODP.NET
値のバインド
Mark A. Williams著
バインド変数およびODP.NETを使用して、.NETアプリケーションのパフォーマンスを改善します。
.NETアプリケーションで、Oracleデータベースからデータにアクセスする方法はたくさんあります。 機能とパフォーマンスの観点から、Oracle Data Provider for .NET(ODP.NET)が.NETアプリケーションとOracle Databaseをつなぐ最適な選択肢となります。
この新しいコラムでは、ODP.NET 10gの主要な機能による.NETアプリケーションのメリットを中心に説明します。 最初のトピックは、ODP.NET 10gと組み合わせたバインド変数の使用方法です。
バインド変数の使用
ODP.NET 10gアプリケーションを正しく実行および拡張するためのもっとも簡単で最適な方法は、バインド変数を正しく使用することです。 バインド変数によって多くのタイプのアプリケーションのパフォーマンスが向上しますが、ここではODP.NET 10gによるバインド変数の使用について説明します。
バインド変数は、SQL文中のプレースホルダです。 たとえば、Oracle Databaseに付属している HR サンプル・スキーマを使用すると、バインド変数を使用しない通常の SELECT 文は次のようになります。
select country_name
from hr.countries
where country_id = 'UK'
このように、文の WHERE 句に 'UK' リテラル・テキストが指定されました。 一か所の簡単な変更をおこない、この文にバインド変数を使用できます。
select country_name
from hr.countries
where country_id = :country_id
バインド変数バージョンの文では、 'UK' リテラル・テキストを :country_id プレースホルダに置き換えました。 バインド変数識別子は、単一のコロン(":")で開始されます。これが、バインド変数をSQL文で記述する方法です。
バインド変数の使用を示す SELECT 文を使用していますが、 UPDATE 、 INSERT 、および DELETE 文でもバインド変数を使用できます。 同じ countries 表の UPDATE 文でバインド変数を使用する例を以下に示します。
update hr.countries
set country_name = :country_name
where country_id = :country_id
バインド変数が重要な理由
Oracle Database 10gがOracle Database 10gがSQL文を受け取った場合、共有プール(メモリ領域)をチェックして、文がすでに存在しメモリに格納されているかどうかを確認します。 文がメモリに存在し、Oracle Database 10gがその文を再利用できる場合、データベースは文を解析および最適化するタスクをスキップできます。 バインド変数を使用すると、SQL文がメモリに格納される可能性が大幅に高まります。これによって、そのSQL文を必要とする次の操作で迅速にそのSQL文を使用できます。
文が共有プールに存在しない場合、データベースで文を解析し、最適化する必要があります。これによって、パフォーマンスが低下する可能性があります。 文の解析および最適化には、CPUサイクルが使用されます。CPUサイクルが増えるほど、処理が遅くなります。 また、解析および最適化では、ラッチと呼ばれるメカニズムを通じて共有プールのさまざまな部分をロックします。 一度に単一のプロセスのみがラッチを使用できるので、共有プールのラッチが増えるとデータベースの競合が発生します。
単一ユーザー・システムでは、発生するラッチと文の解析および最適化にかかる時間が重要ではない場合があります。 ただし、ユーザーがシステムに追加されたり、アプリケーションの追加のコピーが実行される場合、これらのイベントがすぐに増える可能性があります。場合によっては、システムが使用できなくなります。
ODP.NET 10gのバインド変数の実装
ODP.NET 10gプログラムでバインド変数を使用するには、 OracleParameter クラスを使用して.NETコードで各バインド変数を表します。 OracleParameterCollection クラスは、名前が示すとおり、各文の OracleCommand オブジェクトに関連づけられた OracleParameter オブジェクトを含むコレクション・クラスです。 OracleCommand クラスは、SQL文をデータベースに渡し、結果をアプリケーションに返します。
ODP.NET 10gでは、バインド変数の2つのモード(位置によるバインド(デフォルト)と名前によるバインド)を使用できます。 OracleCommand ブール型プロパティの BindByName (デフォルトはfalse)でモードを設定します。 位置によるバインドのモードを使用する場合、SQL文に示されている順序でパラメータを OracleParameterCollection コレクションに追加する必要があります。 Add メソッドと Parameters プロパティを使用して、コマンド・オブジェクトのコレクションにパラメータを追加します。 名前によるバインドのモードを使用する場合、任意の順序でパラメータをコレクションに追加できますが、パラメータ・オブジェクトの ParameterName プロパティをSQL文のバインド変数識別子と同じ値に設定する必要があります。
バインディング・モード(位置または名前)に加えて、各パラメータ・オブジェクトにいくつかのほかのプロパティを設定します。
バインド変数は、出力、入力、または入力/出力パラメータとして使用できます。 Direction プロパティを使用して、各パラメータの適切な方向を示します。 Direction プロパティのデフォルト値は、 Inputです。 OracleDbType プロパティを使用して、パラメータが数値、日付、 VARCHAR2 などであるかどうかを示します。 VARCHAR2 データ型などの可変長のデータ型を使用する場合、 Size プロパティを使用してパラメータに格納されるデータの最大サイズを示します。 Value プロパティは、文の実行前(入力パラメータの場合)、文の実行後(出力パラメータの場合)、または文の実行前後(入力/出力パラメータの場合)のパラメータ値を格納します。
リスト1の Main メソッドは、これらの概念を統合して、 SELECT 文のバインド変数を使用します。 Main メソッドの主要な部分を以下に示します。
OracleCommand cmd =
new OracleCommand();
コマンド・オブジェクト( OracleCommand )を作成します。
OracleParameter p_country_id =
new OracleParameter();
パラメータ・オブジェクト( OracleParameter )を作成します。
p_country_id.OracleDbType = OracleDbType.Varchar2;
p_country_id.Value = "UK";
パラメータ・オブジェクトの OracleDbType および Value プロパティを設定します。
ODP.NETの詳細の確認 Oracle Data Provider for .NET開発者ガイド
ダウンロード ODP.NET 10g Oracle Developer Tools for Visual Studio .NET
Direction プロパティにデフォルト値の Input が使用され、 Size プロパティが設定されないことに注意してください。 オブジェクトが入力パラメータなので、 Size プロパティを設定する必要はありません。データ・プロバイダは、値からサイズを決定できます。
cmd.Parameters.Add(p_country_id);
パラメータをコレクションに追加します。
リスト1のサンプル・アプリケーションを実行するには、.NETコンソール・アプリケーションを作成し、メソッドの本体としてリスト1のコードを使用する Main メソッドを作成します。 ODP.NET 10gアセンブリの参照をプロジェクトに追加し、コード・モジュールの上部に Oracle .DataAccess.Client 名前空間を設定する必要があります。 参照を追加するには、Microsoft Visual Studio .NET 2003メニュー・バーの「 プロジェクト 」→「 参照の追加 」を選択し、参照の追加 ダイアログ・ボックスの「 Oracle .DataAccess.dll 」を選択します。 名前空間を設定するには、コード・モジュールの上部に using Oracle.DataAccess.Client; を追加します。 出力は次のようになります。
C:\VTB\bin\Release>ValuesThatBind.exe
Country Name: United Kingdom
コード・リスト1: バインド変数の使用
static void Main(string[] args)
{
string constr = "User Id="hr;" Password="hr;" Data Source=oramag";
OracleConnection con = new OracleConnection(constr);
con.Open();
StringBuilder sbSQL = new StringBuilder();
sbSQL.Append("select country_name ");
sbSQL.Append("from countries ");
sbSQL.Append("where country_id = :country_id");
OracleCommand cmd = new OracleCommand();
cmd.Connection = con;
cmd.CommandText = sbSQL.ToString();
OracleParameter p_country_id = new OracleParameter();
p_country_id.OracleDbType = OracleDbType.Varchar2;
p_country_id.Value = "UK";
cmd.Parameters.Add(p_country_id);
OracleDataReader dr = cmd.ExecuteReader();
if (dr.Read())
{
Console.WriteLine("Country Name: {0}", dr.GetOracleString(0));
}
dr.Dispose();
p_country_id.Dispose();
cmd.Dispose();
con.Dispose();
}
バインド変数の使用の継続
このコラムでは、ODP.NET 10gと組み合わせて.NETアプリケーションの簡単なバインド変数を使用する方法を説明しました。 バインド変数のメリットを確認するために、バインド変数を使用したり削除したりして独自のアプリケーションをテストすることを推奨します。
Mark A. Williams ( mawilliams@cheshamdbs.com )氏は、2004年にApressから発行された『 Pro .NET Oracle Programming 』の著者で、Oracle ACEおよびOracle Certified Professional DBAの資格をもっています。 また、Oracle on Windowsソリューションに取り組み、Oracle Technology NetworkのOracle Data Provider for .NETに関するフォーラムに貢献しています。