FireDAC での BLOB ストリーミングのサポート
コマンドの操作(FireDAC) への移動
BLOB ストリーミング技術により、データベースとの BLOB パラメータ値のストリーミングが実装されています。これにより、BLOB 値を "値で" 転送するのではなく "参照で" 転送できます。この技術のよい点は次のとおりです。
- クライアント側でのメモリ使用量が最小限に抑えられます。これに対して、"値で" 転送する場合は、BLOB 値のサイズの 3 ~ 4 倍に等しいメモリ量が必要になります。
- "値で" 転送する場合に比べて、パフォーマンスが 1.5 ~ 2 倍良くなります。
- BLOB 値を "チャンク単位で" 更新できます。これに対して、"値で" 転送する場合は、BLOB 値全部の更新のみ可能です。
悪い点は次のとおりです。
- ほとんどのデータベースの場合に、データ型やエンコーディングの変換が実行されません。
- 列ではなくコマンド パラメータの場合にのみサポートされています。
BLOB 値を "値で" 転送する API は次のとおりです。
BLOB ストリーミング API には次のものがあります。
使用法
FireDAC には、2 種類の BLOB ストリーミング(外部ストリームと内部ストリーム)が用意されています。
外部ストリーム
外部ストリームは、アプリケーションから FireDAC に提供されます(FireDAC の外部にある)。FireDAC がこのストリームを読み書きします。外部ストリームは、すべてのデータベースの場合にサポートされています。
外部ストリーミングを使用するには、アプリケーションで以下を行わなければなりません。
- 必要に応じて、パラメータの DataType を ftOraBlob、ftBlob、ftMemo、ftWideMemo などの BLOB データ型のいずれかに設定します。 設定しない場合、AsStream プロパティへの次回の割り当てでは、パラメータのデータ型が暗黙に ftStream に設定されます。
- 必要に応じて、パラメータの ParamType を設定します。 これでストリームの転送モード(次のいずれか)が指定されます。
- ptInput - ストリームが読み取られ、データベースの BLOB 値に書き込まれます。
- ptOutput - データベースの BLOB 値が読み取られ、ストリームに書き込まれます。
- パラメータの AsStream プロパティにストリーム参照を割り当てます。 この場合は、FireDAC がこのストリーム参照の所有者になります。 このオブジェクトは、クエリの準備解除の後または次回の値割り当ての後に解放されます。 あるいは、アプリケーションでパラメータの SetStream メソッドを使用して所有先を制御してもかまいません。 ストリームは現在のストリーム位置から使用されます。
- SQL コマンドを実行します。
次に例を示します。
FDQuery1.SQL.Text := 'INSERT INTO tab (blobdata) VALUES (:blobdata)';
FDQuery1.Params[0].DataType := ftBlob;
// FireDAC takes ownership of the stream object
FDQuery1.Params[0].AsStream := TFileStream.Create('data.bin', fmOpenRead);
FDQuery1.ExecSQL;
内部ストリーム
内部ストリームは、FireDAC からアプリケーションに提供されます(FireDAC の内部にある)。アプリケーションがこのストリームを読み書きします。内部ストリームは、DBMS BLOB ストリーミング API のシン オブジェクト ラッパーです。そのため、データベースに BLOB ストリーミング用の API がない場合、そのデータベースについては内部ストリームがサポートされていない可能性があります。また、Seek、Position、Size などの操作の API がデータベースにない場合は、それらのメソッドが機能しないなど、内部ストリームの機能が制限されている可能性があります。詳細については、「サポートされているドライバ」を参照してください。
内部ストリーム操作の要件は次のとおりです。
- まず、SQL コマンドを実行する必要があります。 内部ストリームには、実行後にのみアクセスできます。
- 明示的なトランザクションの内部で実行する必要があります。 これはほとんどの DB API の要件です。
- 内部ストリームの参照をできるだけ早く解放する必要があります。 これは、Commit や Unprepare、CloseStreams などの一部の操作で内部ストリーム オブジェクトが解放される可能性があるからです。
- 自動参照カウントを使用するコンパイラの内部ストリームに明示的な変数を使用します(以下のコード参照)。
内部ストリーミングを使用するには、アプリケーションで以下を行わなければなりません。
- トランザクションを開始します。
- パラメータの DataType を ftStream に設定します。
- パラメータの StreamMode を必要な内部ストリーム モード(次のいずれか)に設定します。
- smOpenRead - データベースの BLOB 値を読み取ります。
- smOpenWrite - DB BLOB 値を書き込みます。
- smOpenReadWrite - データベースの BLOB 値を読み取り書き込みます。
- 必要に応じて、パラメータの ParamType を必要なパラメータ モードに設定します。 外部ストリーミングとは異なり、ParamType は内部ストリーム参照の初期化に影響を及ぼし、ストリームを開くモードに影響を及ぼすのは、パラメータの StreamMode のみであることに注意してください。
- 必要に応じて、パラメータ FDDataType を、BLOB データ型のいずれかに設定します(
dtHBlob
、dtBlob
、dtHMemo
、dtWideHMemo
など)。デフォルトでの値は、ftBlob
またはftOraBlob
です(FDDataType が設定されてない場合)。 - SQL コマンドを実行します。 この結果、内部ストリーム参照が返されます。
- 内部ストリーム参照を読み書きします。
- 必要に応じて、データセットまたはコマンドの CloseStreams メソッドを呼び出して、データベースの API バッファをフラッシュし内部ストリームを閉じます。 これは ODBC ベース、InterBase、および Firebird のドライバには必須ですが、その他のドライバの場合には、これを行っても何も効果はありません。
- トランザクションを終了します。
例:
FDConnection1.StartTransaction;
try
FDQuery1.SQL.Text := 'INSERT INTO tab (blobdata) VALUES (:blobdata)';
FDQuery1.Params[0].DataType := ftStream;
FDQuery1.Params[0].StreamMode := smOpenWrite;
FDQuery1.ExecSQL;
oStr := TFileStream.Create('data.bin', fmOpenRead);
try
// Database receives a copy of the original stream
{$IFDEF AUTOREFCOUNT}
oInt := FDQuery.Params[0].AsStream;
oInt.CopyFrom(oStr, -1);
oInt := nil;
{$ELSE}
FDQuery1.Params[0].AsStream.CopyFrom(oStr, -1);
{$ENDIF}
finally
// The user is responsible for freeing the original stream
oStr.Free;
end;
FDQuery1.CloseStreams;
FDConnection1.Commit;
except
FDConnection1.Rollback;
raise;
end;
SQL Server の FILESTREAM
SQL Sever FILESTREAM のサポートは内部ストリーミングの特殊なケースです。サーバー セットアップの詳細については、SQL Server FILESTREAM のドキュメントを参照してください。
テーブル DDL の場合、"data" は FILESTREAM 列で、"rowguid" は rowguidcol 列です。 FILESTREAM 列を持つテーブルには、ストリームを識別するための rowguidcol 列が必要です。
create table FSTab (
id int IDENTITY(1,1) NOT NULL Primary Key,
name varchar(100) NOT NULL,
data varbinary(max) filestream NULL,
rowguid uniqueidentifier NOT NULL rowguidcol unique DEFAULT (newid())
)
データを取得する SQL コマンドの場合、"data" 列は SELECT リストから除外されます。FILESTREAM ストリーミングを使用するのではなく、FILESTREAM の内容を "値で" 転送するからです。 代わりに、パラメータのある SQL コマンドを使用する場合、その値はサーバー側では "data.PathName()" に設定されます。
select :p = data.PathName() from FSTab where id = :id
FireDAC で FILESTREAM ストリーミングを使用するには:
- パラメータを次のように設定します。
- DataType を次の値のいずれかに設定します。
- ftBlob(外部ストリームを操作する場合や BLOB 値を "値で" 転送する場合)
- ftStream(内部の FILESTREAM ストリームを返す場合)
- FDDataType を dtHBFile に設定します。
- ParamType を ptOutput に設定します。
- StreamMode を次の値のいずれかに設定します。
- smOpenWrite(FILESTREAM に書き込む場合)
- smOpenRead(FILESTREAM から読み取る場合)
- smOpenReadWrite(FILESTREAM に対して読み書きする場合)
- DataType を次の値のいずれかに設定します。
- トランザクションを開始します。
- PathName() の結果をパラメータに入れて返す SQL コマンドを実行します。これは BLOB ストリーミングを実行することになります。上記の設定は、アプリケーションでこのパラメータに内部ストリーミングを使用しようとしている特有のしるしです。
- トランザクションを終了します。
次に例を示します。
FDConnection1.StartTransaction;
try
FDQuery.SQL.Text := 'select :p = data.PathName() from FSTab where id = :id';
FDQuery.Params[0].DataType := ftStream;
FDQuery.Params[0].FDDataType := dtHBFile;
FDQuery.Params[0].ParamType := ptOutput;
FDQuery.Params[0].StreamMode := smOpenRead;
FDQuery.Params[1].AsInteger := 123;
FDQuery.OpenOrExecute;
// TFDParam.AsStream returns reference to internal low-level stream
FDQuery.Params[0].AsStream.Read(Buffer, Length(Buffer));
FDConnection1.Commit;
except
FDConnection1.Rollback;
raise;
end;
サポート対象ドライバ
ドライバ | 外部ストリーミング | 内部ストリーミング |
---|---|---|
サポート。 |
サポート。CloseStreams への呼出しを要求します。ストリームに書き込む前に、サイズを ストリームの最大長 に設定します。 | |
サポート。 |
サポート。 | |
サポート。 |
サポート。CloseStreams の呼び出しが必要。 | |
サポート。 |
サポート。CloseStreams の呼び出しが必要。 | |
サポート。 |
サポート。CloseStreams の呼び出しが必要。 | |
サポート。 |
サポート。CloseStreams の呼び出しが必要。 | |
サポート。 |
サポート。CloseStreams の呼び出しが必要。 | |
サポート。 |
サポート。非 FILESTREAM データ型用 CloseStreams の呼び出しが必要。FILESTREAM には特別な処理が必要。 | |
サポート。DataType を ftBlob に設定。 |
未サポート。 | |
サポート。 |
サポート。CloseStreams の呼び出しが必要。 | |
サポート。DataType を ftOraBlob または ftOraClob に設定。 |
サポート。DataType を ftOraBlob または ftOraClob に設定。挿入時には、BLOB/CLOB フィールドの次のような特殊な初期化が必要。
| |
サポート。 |
サポート。OidAsBlob 接続パラメータを Yes に設定。 | |
サポート。 |
未サポート。 | |
サポート。 |
サポート。CloseStreams の呼び出しが必要。 | |
サポート。 |
サポート。CloseStreams の呼び出しが必要。 |
関連項目
サンプル
- FireDAC TFDQuery Blob サンプル
- FireDAC TFDQuery BlobStreams サンプル
- Object Pascal/Database/FireDAC/Samples/DBMS Specific/MSSQL/FileStream