今回はOracle Data Provider for .NET(以下、ODP.NET)を利用してOracleデータベースへアクセスするための詳細な説明と、パフォーマンスを向上させるためのコーディング・テクニックについて説明します。
LOBデータの操作とチューニング
LOBとはラージオブジェクト(Large Object)のことで、ギガバイト級の大きなファイルサイズのデータを扱うオブジェクトです。LOBのデータ型は主にBLOB(Binary Large Object)とCLOB(Character Large Object)の2種類に分類されます。
BLOBアクセスの基本操作
まず、ODP.NETからBLOBへのアクセス方法を説明します。
手順1
テスト用のBLOBフィールドを含んだテーブルを作成します。
create table blob_test(
blob_id number(4,0) primary key,
blob_fld blob
); |
手順2
以下のサンプル用ビットマップ・イメージファイルをダウンロードして、Cドライブのtempディレクトリに保存してください。
手順3
BLOBフィールドへの値の代入は、以下のようなコードになります。
Dim fs As New System.IO.FileStream("c:\temp\odp.bmp", _
IO.FileMode.Open, IO.FileAccess.Read)
Dim blobData(fs.Length) As Byte
fs.Read(blobData, 0, fs.Length)
Dim cnn As New OracleConnection( _
"user id=scott;password=tiger;data source=orcl")
Dim strSql As String = _
"insert into blob_test(blob_id, blob_fld) " & _
"values(1, :blobdata)"
Dim cmd As New OracleCommand(strSql, cnn)
cnn.Open()
Dim pBlob As OracleParameter = _
cmd.Parameters.Add("blobdata", OracleDbType.Blob)
pBlob.Value = blobData
cmd.ExecuteNonQuery() |
リスト1 BLOBフィールドへファイルを挿入するサンプルコード(VB.NET) |
System.IO.FileStream fs =
new System.IO.FileStream("c:\\temp\\odp.bmp",
System.IO.FileMode.Open, System.IO.FileAccess.Read);
byte[] blobData = new byte[fs.Length];
fs.Read(blobData, 0,(int)fs.Length);
OracleConnection cnn =
new OracleConnection(
"user id=scott;password=tiger;data source=orcl");
String strSql =
"insert into blob_test(blob_id, blob_fld) " +
"values(1, :blobdata)";
OracleCommand cmd = new OracleCommand(strSql, cnn);
cnn.Open();
OracleParameter pBlob =
cmd.Parameters.Add("blobdata", OracleDbType.Blob);
pBlob.Value = blobData;
cmd.ExecuteNonQuery(); |
リスト2 BLOBフィールドへファイルを挿入するサンプルコード(C#) |
OracleParameterオブジェクトのOracleDbTypeプロパティをBlobに指定し、画像データなどのバイナリデータを格納します。
注意:今回のサンプルコードはすべて、ODP.NETの名前空間の指定(Oracle.DataAccess.ClientとOracle.DataAccess.Types)を省略して記述してあります。
手順4
BLOBフィールドから値を取得し、PictureBoxに表示するコードは以下になります。
Dim cnn As New OracleConnection( _
"user id=scott;password=tiger;data source=orcl")
Dim strSql As String = _
"select blob_fld from blob_test where blob_id=1"
Dim cmd As New OracleCommand(strSql, cnn)
cnn.Open()
Dim dr As OracleDataReader = cmd.ExecuteReader
If dr.Read Then
Dim blob As OracleBlob = dr.GetOracleBlob(0)
Dim ms As New System.IO.MemoryStream(blob.Value)
PictureBox1.Image = New Bitmap(ms)
End If |
リスト3 BLOBフィールドに格納された画像データをPictureBoxに表示するサンプルコード(VB.NET) |
OracleConnection cnn =
new OracleConnection(
"user id=scott;password=tiger;data source=orcl");
String strSql =
"select blob_fld from blob_test where blob_id=1";
OracleCommand cmd = new OracleCommand(strSql, cnn);
cnn.Open();
OracleDataReader dr = cmd.ExecuteReader();
if(dr.Read())
{
OracleBlob blob = dr.GetOracleBlob(0);
System.IO.MemoryStream ms =
new System.IO.MemoryStream(blob.Value);
pictureBox1.Image = new Bitmap(ms);
} |
リスト4 BLOBフィールドに格納された画像データをPictureBoxに表示するサンプルコード(C#) |
BLOB型で格納された情報を取得するには、OracleDataReaderオブジェクトのGetOracleBlobメソッドを使用し、結果をOracleBlobオブジェクトに格納します。
LOBデータ取得時のパフォーマンス・チューニング
LOBの列型を含むOracleDataReaderが作成されると、OracleDataReaderを作成したOracleCommandのInitialLOBFetchSizeプロパティの値がOracleDataReaderによってチェックされ、LOBの列データをすぐにフェッチする必要があるかどうかが判断されます。デフォルトでは、InitialLOBFetchSizeは「0」に設定されています。
OracleCommandのInitialLOBFetchSizeプロパティの値が「0」のままであれば、LOBデータ全体の取得は、アプリケーションによってデータが明示的に要求されるまで延期されます。InitialLOBFetchSizeプロパティが「0」以外の値に設定されていると、その値の文字数またはbyte数までLOBデータが即座にフェッチされます。
InitialLOBFetchSizeプロパティがデフォルトの「0」の場合、OracleDataReaderのGetOracleBlob/GetOracleClobメソッドを起動して、OracleBlob/OracleClobオブジェクトを取得できます。ただしInitialLOBFetchSizeが「0」以外の値に設定されていると、GetOracleBlob/GetOracleClobメソッドは無効です。その場合には、GetBytes/GetCharsメソッドをそれぞれ使用してBLOB/CLOBデータをフェッチする必要があります。InitialLOBFetchSizeを指定したコードは以下のようになります。
Dim cnn As New OracleConnection( _
"user id=scott;password=tiger;data source=orcl")
Dim strSql As String = _
"select blob_fld from blob_test where blob_id=1"
Dim cmd As New OracleCommand(strSql, cnn)
cnn.Open()
cmd.InitialLOBFetchSize = 32767
Dim dr As OracleDataReader = cmd.ExecuteReader
If dr.Read Then
Dim byteArray(32767) As Byte
Dim numBytesRead As Long = _
dr.GetBytes(0, 0, byteArray, 0, 32767)
Dim ms As New System.IO.MemoryStream(byteArray)
PictureBox1.Image = New Bitmap(ms)
End If |
リスト5 InitialLOBFetchSizeを指定して、BLOBフィールドに格納された画像データをPictureBoxに表示するサンプルコード(VB.NET) |
OracleConnection cnn =
new OracleConnection(
"user id=scott;password=tiger;data source=orcl");
String strSql =
"select blob_fld from blob_test where blob_id=1";
OracleCommand cmd = new OracleCommand(strSql, cnn);
cnn.Open();
cmd.InitialLOBFetchSize = 32767;
OracleDataReader dr = cmd.ExecuteReader();
if(dr.Read())
{
byte [] byteArray = new byte[32767];
long numBytesRead =
dr.GetBytes(0, 0, byteArray, 0, 32767);
System.IO.MemoryStream ms =
new System.IO.MemoryStream(byteArray);
pictureBox1.Image = new Bitmap(ms);
} |
リスト6 InitialLOBFetchSizeを指定して、BLOBフィールドに格納された画像データをPictureBoxに表示するサンプルコード(C#) |
InitialLOBFetchSizeを「0」以外の値に設定すると、OracleBlob/OracleClobオブジェクトを使用してLOBデータを取得するよりも、高いパフォーマンスを得られることがあります。OracleDataReaderからOracleBlob/OracleClobオブジェクトを取得する必要のないアプリケーションで、LOB列データがそれほど大きくない場合がこれに該当します。InitialLOBFetchSizeは、問い合わせで返されるLOB列データのサイズがすべての行でほぼ同じ場合、特に便利です。
一般にInitialLOBFetchSizeは、問い合わせで返される行のうち、80%を超える行のLOBデータのサイズよりも大きな値に設定することをお勧めします。例えば、80%の行でLOBデータのサイズが1Kbytesよりも小さく、20%の行で1Mbytesよりも大きい場合には、InitialLOBFetchSizeを1Kbytesに設定します。(次ページへ続く)