Oracle 11g (11.2.0.3) システムから BLOB をエクスポートする必要があります。このプロセスは、32,767 バイト未満の BLOB (JPG 写真) に最適です。dbms_log.read & utl_file.put_raw を使用して、5 秒以内に ~4000 枚の写真をデータベース サーバーのローカル ディレクトリにエクスポートできます。ファイルが読み取りバッファーの 32,767 バイトの制限を超えている場合、ここからパフォーマンスの問題が発生します。正確なパフォーマンスの問題について同様の投稿を見たことがありますが、提供された解決策はすでに調査されていますが、成功していません。監視ツールに基づいて、CPU、I/O、およびメモリは、エクスポート中に圧迫されていません。32,767 バイト単位でつなぎ合わせる必要がある大きな BLOB (すべてのサイズが 100K 未満) のエクスポートが、32,767 バイト未満の BLOB と比較して非常に遅い理由を理解しようとしています。
32,767 バイトを超えるファイルで BLOB エクスポートの速度が低下したことを経験した人はいますか?
DECLARE
CURSOR cur_photo IS
select substr(c.custnum, -7, length(c.custnum)) custnum,
cp.cust_id,
cp.photo
from customer c
inner join customer_photo cp
on c.cust_id = cp.cust_id
inner join customer_def_grp_value cdv
on c.cust_id = cdv.cust_id;
select_sql varchar2(225);
l_file UTL_FILE.FILE_TYPE;
l_buffer RAW(32767);
l_amount PLS_INTEGER := 32767;
l_pos PLS_INTEGER := 1;
l_blob BLOB;
l_blob_len PLS_INTEGER;
l_filename varchar2(225);
error_number varchar2(225);
error_message varchar2(225);
BEGIN
--dbms_output.put_line('Starting at: ' || to_char(systimestamp, 'DD-MON-YYYY HH:MI:SS.FF6'));
--DBMS_OUTPUT.ENABLE (buffer_size => NULL);
FOR custphoto IN cur_photo LOOP
--dbms_output.put_line('In the loop ' || custphoto.cust_id);
select_sql := 'SELECT photo FROM customer_photo WHERE cust_id = :cust_id';
--dbms_output.put_line('Statement: ' || select_sql);
EXECUTE IMMEDIATE select_sql INTO l_blob using custphoto.cust_id;
l_blob_len := DBMS_LOB.getlength(l_blob);
--dbms_output.put_line('BLOB length: ' || l_blob_len);
-- Set the filename
l_filename := custphoto.custnum || '.jpg';
--dbms_output.put_line('Filename: ' || l_filename);
-- Open the destination file.
l_file := UTL_FILE.fopen('jpeg', l_filename, 'wb', 32767);
--dbms_output.put_line('Start Export at: ' || to_char(systimestamp, 'DD-MON-YYYY HH:MI:SS.FF6'));
IF l_blob_len < 32767 then
--dbms_output.put_line('BLOB < 32767 bytes');
DBMS_LOB.read(l_blob, l_blob_len, l_pos, l_buffer);
UTL_FILE.put_raw(l_file, l_buffer, TRUE);
ELSE -- write in pieces
--dbms_output.put_line('BLOB >= 32767 bytes');
WHILE l_pos < l_blob_len LOOP
DBMS_LOB.read(l_blob, l_amount, l_pos, l_buffer);
UTL_FILE.put_raw(l_file, l_buffer, TRUE);
l_pos := l_pos + l_amount;
END LOOP;
END IF;
-- Close the file.
UTL_FILE.fclose(l_file);
-- Reset the pos for the next jpg file
l_pos := 1;
END LOOP;
EXCEPTION
WHEN OTHERS THEN
-- Close the file if something goes wrong.
error_number := sqlcode;
error_message := substr(sqlerrm, 1, 100);
dbms_output.put_line('Error Number: ' || error_number);
dbms_output.put_line('Error Message: ' || error_message);
utl_file.fclose_all;
RAISE;
END;
BLOB のエクスポートに関する洞察をお寄せいただきありがとうございます。