はじめに
.NETアプリケーションからOracleへ接続するための最善の方法は、Oracle社が提供している「Oracle Data Provider for .NET」(以下、ODP.NET)を使うことです。今回は、ODP.NETを利用してデータベースへのアクセスを高速化する手法を説明します。
対象読者
- Visual Basic、もしくはC#を使ってプログラムを作ったことのある人。
- Oracleデータベース対応アプリケーション開発に興味のある人。
必要な環境
- Visual Studio 2003/2005/2008
- ODP.NET 11.1.0.6.20 以上(注1)
- Oracle Database 11g Release 1以上
ODP.NETのインストーラは、Oracle Technology Network(以下、OTN)からダウンロードできます。
データベースへのアクセス速度を向上させる方法
データベースへのアクセス速度を上げるには、さまざまな方法があります。前回の『ODP.NET パフォーマンスチューニング 第1回』では以下の3つの方法を説明しました。
- コネクションプーリングを利用する
- データベースとのラウンドトリップを少なくする
- SQLの解析を少なくする
今回は、以下の3つの方法を利用して、Oracle データベースとの接続パフォーマンスを向上させる方法を説明します。
- データの一括コピー
- SQLの実行結果をキャッシュする
- ラージ・オブジェクトへの高速アクセス
データの一括コピー
一括コピー機能は、Oracleデータベース以外のデータソースからOracleデータベース内の表に対してデータを高速に一括ロードします。例えば、ExcelファイルからOracleデータベースにデータを取り込む際は、通常ですとExcelファイルをDataTable、もしくはDataReaderで読み込み、行単位でOracleデータベースにInsertしていたかと思いますが、一括コピー機能を利用すれば、複数行を一回でOracleデータベースの表に取り込むことができます。
ODP.NETでこの一括コピー機能を利用するために、「OracleBulkCopy」クラスが用意されています。OracleBulkCopyクラスのメソッドとプロパティとして以下が用意されています。
設定項目 | 内容 |
BatchSize | バッチとしてデータベースに送信される行数を指定します |
BulkCopyOptions | Oracleデータベースが一括コピー操作の実行に使用するOracleConnectionオブジェクトを指定します |
BulkCopyTimeout | 中断される前に一括コピー操作が完了するまでの秒数を指定します |
ColumnMappings | データ・ソースと保存先表間の列マッピングを指定します |
Connection | Oracleデータベースが一括コピー操作の実行に使用するOracleConnectionオブジェクトを指定します |
DestinationTableName | データがロードされるデータベース表を指定します |
NotifyAfter | 通知イベントが生成される前に処理された行数を定義します |
上記プロパティの太字の部分はOracleBulkCopyを実行する際に必要なプロパティとなりますので、必ず設定してください。「OracleBulkCopy」クラスの「WriteToServer」メソッドを実行すると、「DestinationTableName」プロパティで指定されたデータベース表にデータが格納されます。以下のサンプルコードでは、Excelに格納されたデータをOracle Databaseに一括コピー機能を利用して取り込んでいます。
'// Excelデータの取得 Dim eConn As New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;" & _ "Data Source=C:\\Temp\\SmplData.xls;Extended Properties=""Excel 8.0;HDR=YES;"";") eConn.Open() Dim cmdFrom As New OleDbCommand("Select EMPID,EMPNAME From [Sheet1$]") cmdFrom.Connection = eConn Dim rdrFrom As OleDbDataReader = cmdFrom.ExecuteReader '// Oracle Databaseへの接続 Dim oConn As New OracleConnection("User Id=scott;Password=tiger;Data Source=orcl11g") oConn.Open() '// インスタンス生成時コンストラクタにConnectionを指定 Dim obCopy As New OracleBulkCopy(oConn) '// データがロードされるデータベース表を指定 obCopy.DestinationTableName = "emp" '// データ・ソースと保存先表間の列マッピングを指定 obCopy.ColumnMappings.Add("empid", "empno") obCopy.ColumnMappings.Add("empname", "job") '// BulkCopyの実行 obCopy.WriteToServer(rdrFrom)
// Excelデータの取得 OleDbConnection eConn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;" + "Data Source=C:\\Temp\\SmplData.xls;Extended Properties=\"Excel 8.0;HDR=YES;\";"); eConn.Open(); OleDbCommand cmdFrom = new OleDbCommand("Select EMPID,EMPNAME From [Sheet1$]"); cmdFrom.Connection = eConn; OleDbDataReader rdrFrom = cmdFrom.ExecuteReader(); // Oracle Databaseへの接続 OracleConnection oConn = new OracleConnection("User Id=scott;Password=tiger;Data Source=orcl11g"); oConn.Open(); // インスタンス生成時コンストラクタにConnectionを指定 OracleBulkCopy obcopy = new OracleBulkCopy(oConn); // データがロードされるデータベース表を指定 obcopy.DestinationTableName = "emp"; // データ・ソースと保存先表間の列マッピングを指定 obcopy.ColumnMappings.Add("empid", "empno"); obcopy.ColumnMappings.Add("empname", "job"); // BulkCopyの実行 obcopy.WriteToServer(rdrFrom);
SQLの実行結果をキャッシュする
SQLの実行結果をキャッシュしておくことで、繰り返し実行される問合わせのパフォーマンスを向上させることができます。この結果をキャッシュする機能はOracle Database 11gから追加された「リザルト・キャッシュ」です。この「リザルト・キャッシュ」を利用することにより、SQL検索結果のみキャッシュするので、従来のキャッシュに比べ、メモリの使用効率をあげ、レスポンスの高速化をはかることができます。以下の図は、従来のキャッシュと結果キャッシュの違いを表しています。
SQLの結果キャッシュによってキャッシュされた情報はSGA上(共有プール内の領域)に格納され、ユーザ間でその情報が共有されます。定型的なレポートのクエリーなど、大量データにアクセスするが結果として返す行が少量な場合に非常に有効な機能です。
リザルト・キャッシュに格納されたキャッシュの結果は以下の条件で無効化されます。
- サーバとの通信時にキャッシュした結果セットが更新などによって無効となったことがサーバから通知された
- CLIENT_RESULT_CACHE_LAGで指定された時間、サーバとの通信が発生しなかった
リザルト・キャッシュの利点として、既存のアプリケーションを変更せずにこのキャッシュ機能を利用することができます。この機能の設定と有効化はOracle Databaseの「RESULT_CACHE_MODE」初期化パラメータを変更します。設定項目は以下です。
設定項目 | 説明 |
MANUAL (デフォルト) |
ユーザが手動でリザルト・キャッシュを行う指定をした場合のみ、リザルト・ キャッシュの機能が使用される |
FORCE | 常にリザルト・キャッシュの機能が働く |
Oracle Databaseの設定は、以下のように初期化パラメータの変更SQLを実行します。
alter system set RESULT_CACHE_MODE = 'FORCE';
もし、RESULT_CACHE_MODEの値が「MANUAL」となっていた場合は、SQLの中にヒント句を入れることにより、クライアント・リザルトキャッシュ機能を有効にすることが可能です。
select /*+ result_cache */ first_name, last_name from employees