PreparedStatement pstmt = conn.prepareStatement( 'SELECT BLOB_VALUE FROM TABLEA WHERE ID = ?' ); pstmt.setInt( 1, 1 ); rs = pstmt.executeQuery(); if( rs.next() ){ BLOB blob = (( OracleResultSet ) rs ).getBLOB( 1 ); InputStream ins = blob.getBinaryStream(); bos = new ByteArrayOutputStream(); int len = -1; byte[] buffer = new byte[ バッファサイズ ]; while( ( len = ins.read( buffer ) ) != -1 ){ bos.write( buffer, 0, len ); } blobValue = bos.toByteArray(); }
DB_BLOCK_SIZE、LOB記憶域のCHUNKサイズがともに8192byteの環境で読み込みバッファサイズを64byte~64kbyteまで倍々に増やしながら、50MBのファイルの読み込みに要する時間を測定してみると以下のようになりました。
読み込みバッファサイズ(Byte) | 総読み込み時間(秒) |
---|---|
64 | 80.00 |
128 | 45.02 |
256 | 30.01 |
512 | 25.07 |
1,028 | 25.00 |
2,048 | 24.05 |
4,096 | 24.09 |
8,192 | 16.04 |
16,384 | 14.07 |
32,768 | 13.03 |
65,536 | 12.07 |
ご覧の通り、読み込みバッファサイズを大きくすればするほど読み込みに要する時間も短くなるようです。
ただし、パフォーマンスの向上率は読み込みバッファサイズを大きくすればするほど小さくなります。
ということで、大体CHUNKサイズか、その倍数にしておくのがよいようです。
ただし、CHUNKサイズはLOB領域によって設定を変えられるものなので、プログラムの中にリテラルで埋め込むのはあまりいい方法とは言えません。
Oracle JDBCドライバでサポートされるoracle.sql.BLOB、oracle.saql.CLOBの各クラスにはgetChunkSize()というメソッドが用意されているので、これを呼び出してCHUNKサイズを動的に取得するのがよいでしょう。
BLOB blob = (( OracleResultSet ) rs ).getBLOB( 1 ); int size = blob.getChunkSize(); byte[] buffer = new byte[size];
なお、oracle.sql.BLOB、oracle.saql.CLOBの各クラスにはgetBufferSize()というメソッドも用意されています。
こちらはJDBCドライバの計算によるLOBデータの読込みおよび書込みに使用する理想的なバッファ・サイズを戻すようです。
実際にはCHUNKサイズの倍数で32Kに近い値ということなのですが、"理想的"というだけにgetChunkSize()よりもgetBufferSize()を使う方が理想的なのかもしれません。
BLOB blob = (( OracleResultSet ) rs ).getBLOB( 1 ); int size = blob.getBufferSize(); byte[] buffer = new byte[size];
ただ、上記のテスト結果を見る限りは、どちらを使ってもさほど変わりはないようですが...
【関連エントリ】
[Oracle] LOBデータの基本的な扱い方 2004/12/03
[Oracle] JDBCによるLOBの操作方法 2004/12/06
[Oracle] LOBデータをファイルから直接登録する方法(その1) 2005/01/25
[Oracle] LOBデータをファイルから直接登録する方法(その2) 2005/01/27
[Oracle] LOBデータをファイルに直接出力する方法 2005/02/01
[Oracle] JavaでLOBデータを読み込む際の最適なバッファサイズは? 2005/02/02
[Oracle] LOB記憶特性 その1(STORAGE IN ROW) 2005/08/23
[Oracle] LOB記憶特性 その2(CHUNK) 2005/08/24