単純型のフィールドと異なり、巨大なデータを格納できるフィールド型としてOracleは以下の型を用意しています
-
Long型 / Long raw 型 -
Oracle7以前でも使えます。最大2GBのデータを、テーブルのデータ領域に他のカラムと一緒に格納します。したがって、SELECT文によるテーブルスキャンは相当に遅くなる可能性があります。 -
Clob / Blob型 -
Oracle8以降で使えます。最大4GBのデータを格納できます。データはテーブルデータとは別の領域に格納され、テーブルのデータ領域にはその領域へのポインタのみが格納されるため、SELECT
* FROM Table
..によるテーブルスキャンのパフォーマンスは、Clob/Blobデータのデータサイズの影響を受けません。その代わりに、データアクセスの手順が少し煩雑になりました。 - BFile型 - Oracle8以降。データベースサーバ上のファイルを読み出せます
これらの項目(広義のBlob(Binary Large
Object)型を扱う場合には、アプリケーション設計を誤ると、大量のデータを一度にサーバから取得することになり、絶望的に長い処理時間を要します。一般的に言って、広義のBlobカラムについて、一度にデータを丸々取得すべきレコードは最大一件まででなければ、実用的なパフォーマンスが得られないと考えてよいでしょう。
一方、Oracle8から導入されたClob/ Blob/ BinFile
型を利用する場合は、レコードの先読みが可能で、パフォーマンスの向上が期待できます。その代わり、Clob/
Blob/
BinFile型のカラムは、通常の単純型のフィールドのようにFieldメソッドを用いて簡単にアクセスすることができず、TLOBLocatorオブジェクトを介して間接的にアクセスしなければなりません。
制限事項
Long/Long raw 項目自体は、決してバッファに読み込まれず、
Field関数を実行したときに初めてサーバからデータが取得されます。
また、Long型/Long raw型のフィールドを含むSELECT文を実行した場合、
TOracleQueryは、最大1件分のレコードしかバッファに読み込みません。すなわち
ReadBufferプロパティの設定は無視され、レコードの先読みが行われなくなります。
Long/Long raw 型の output
変数はサポートされません。SELECT文を使った方がよいでしょう。input/output変数として宣言した上で、予め十分な容量のメモリを確保してこれを
input
に与えた時に限り、変数からoutputを取得可能です。詳しくはDOAのヘルプを読み込むなどしてください。
使用例
以下に、Long項目を取得するプログラムの例を示します
// OracleQuery1.SQL = // SELECT Memo FROM TestTable // WHERE MemoId = :MemoId try with OracleQuery1 do begin SetVariable('MemoId', MemoId); Execute; RichEdit1.Lines.Text := Field('Memo').AsString; end; except on E:EOracleError do ShowMessage(E.Message); end;
上記の例のように、文字列フィールドとしてアクセスすることができますが、最も高速にアクセスできるのは、以下のようにVarArrayLock/VarArrayUnlockを用いてデータを(array
of
byteとして)読み込んだバッファのポインタを得る方法です。(VarArrayLock/VarArrayUnlockについてはDelphiのヘルプを参照してください)
// SelectEmpPictureQuery.SQL = // select picture from emp // where empno = :empno try with SelectEmpPictureQuery do begin SetVariable('EMPNO', Emp.EmpNo); Execute; Picture := Field('PICTURE'); //PictureはVariant型です Size := VarArrayHighBound(Picture, 1) + 1; //Variantのサイズを取得 Ptr := VarArrayLock(Picture); //Variantデータへのポインタを取得 try WriteFile('Employee.gif', Ptr^, Size); //ポインタとサイズを用いてアクセスできます finally VarArrayUnlock(Picture); //VarArrayLockと対にして使います end; end; except on E:EOracleError do ShowMessage(E.Message); end;
データを更新するには、以下のようにパラメータ付きクエリーを用います。SetVariableでstring型データを渡すこともできますが、SetLongVariableが効率よい方法です。INSERTの場合も下記と同様です。
//OracleQuery1.SQL = // UPDATE TestTable // SET BinaryData = :BinaryData // WHERE TableKey := TableKey try with OracleQuery1 do begin SetVariable('TableKey', TableKey); SetLongVariable('BinaryData', WavBuffer, WavLength); Execute; end; except on E: EOracleError do showmessage(E.Messasge); end;
DOAでOracle8が導入したBlob型にアクセスするには、TLOBLocator
オブジェクトを利用します。まず、SELECTしたLOBカラムには、TOracleQuery.LOBFieldメソッドでアクセスします。TLOBLocatorはTStreamを継承しているので、Seek/Read/Writeなどのメソッドが利用できます。
var LOB: TLOBLocator; Buffer: array[0..99] of Byte; begin // select lobcolumn from lobtable where id = 1 with LOBQuery do begin Execute; LOB := LOBField('lobcolumn'); if not LOB.IsNull then begin LOB.Seek(-100, soFromEnd); LOB.Read(Buffer, 100); end; end; end;
NULL値がセットされている既存レコードのLOBカラムを更新する場合や、新規レコードを挿入する場合には、以下のようにLOBを新規作成する必要があります。
var LOB: TLOBLocator; Buffer: array[0..99] of Byte; begin // LOBQuery.SQL = // INSERT INTO lobtable (id, lobcolumn) VALUES (:id, empty_blob()) // RETURNING lobcolumn INTO :lobcolumn with LOBQuery do begin SetVariable('id', 1); // 新規BLOBを作成し // RETURNINGで返される変数にバインドする LOB := TLOBLocator.Create(Session, otBLOB); try SetComplexVariable('lobcolumn', LOB); Execute; // 挿入してからTStreamのメソッドでLOBを更新する LOB.Write(Buffer, 100); finally LOB.Free; end; end; end;
以上、簡単に紹介しましたが、詳細については、TOracleQuery.Variables ,
TOracleQuery.SetComplexVariable, TLOBLocatorなどを中心にDOAのヘルプを参照してください。