既存の Oracle BLOB をファイルに移行する必要があるプロジェクトに取り組んでいます。読み取り元の環境は、共有の Oracle 10gR2 サーバーです。現在、UTL_FILE を使用するスクリプトがあります。ただし、プロセスはかなり遅いです。25 GB のサンプル データを抽出するには、約 3 時間かかります。実際に移動するデータは 1 TB 程度です。これを大幅に調整するには、ヘルプ/アドバイスが必要です。
これが私のプロセスです:
- カーソルを開いて BLOB の ID と名前のリストを取得します
- 各ブロブを通過するループを開始します
- カスタム ストアド プロシージャである BLOB2FILE を使用して BLOB を抽出します (Web サイトから取得し、わずかに変更しました)。
コードは次のとおりです。
create or replace
PROCEDURE BLOB2File(
lngBlobID IN NUMBER,
sFileName IN VARCHAR2,
sDir IN VARCHAR2)
AS
iFileLen INTEGER;
iLineLen INTEGER := 32000; -- max line size for utl_file
vStart NUMBER := 1;
vBlob BLOB;
l_output utl_file.file_type;
my_vr RAW(32000);
iTmp INTEGER;
BEGIN
-- get blob details
LOG_IT('Entered. Blob Id: ' || lngBlobID || ', File Name: ' || sFileName || ', Directory: ' || sDir);
SELECT blobData,
lengthb(blobData)
INTO vBlob,
iFileLen
FROM blobTable
WHERE id = lngBlobID;
LOG_IT('Acquired the blob. Blob size: ' || TO_CHAR(iFileLen));
l_output := utl_file.fopen(sDir, sFileName,'wb', iLineLen);
vStart := 1;
iTmp := iFileLen;
-- if small enough for a single write
IF iFileLen < iLineLen THEN
utl_file.put_raw(l_output,vBlob);
utl_file.fflush(l_output);
ELSE -- write in pieces
vStart := 1;
WHILE vStart < iFileLen AND iLineLen > 0
LOOP
dbms_lob.read(vBlob,iLineLen,vStart,my_vr);
utl_file.put_raw(l_output,my_vr);
utl_file.fflush(l_output);
-- set the start position for the next cut
vStart := vStart + iLineLen;
-- set the end position if less than 32000 bytes
iTmp := iTmp - iLineLen;
IF iTmp < iLineLen THEN
iLineLen := iTmp;
END IF;
END LOOP;
END IF;
utl_file.fclose(l_output);
LOG_IT('Exited');
EXCEPTION
WHEN OTHERS THEN
LOG_IT('**ERROR** ' || SQLERRM, SQLCODE, DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);
END;
LOG_IT は、テーブルへのストアド プロシージャ ログです。そこに大きな打撃はないはずです。通常の FETCH の代わりに BULK FETCH を使用して、ステップ 1 の最適化を試みました。しかし、それは重要な結果をもたらしませんでした。
誰かが改善のためのアイデアを提案できますか?