Optimization 将Oracle Blob批量提取到文件中-需要建议/调优帮助

Optimization 将Oracle Blob批量提取到文件中-需要建议/调优帮助,optimization,plsql,oracle10g,blob,utl-file,Optimization,Plsql,Oracle10g,Blob,Utl File,我正在从事一个需要将现有Oracle Blob迁移到文件中的项目。要读取的环境是共享的Oracle 10gR2服务器。目前我有一个使用UTL_文件的脚本。然而,这个过程相当缓慢。提取25 GB的样本数据大约需要3小时。要移动的实际数据约为1 TB。我需要帮助/建议来调整此设置 以下是我的流程: 打开光标以获取blob ID和名称的列表 启动一个循环来遍历每个blob 使用BLOB2FILE提取blob,这是一个自定义存储过程,它从一个网站上获取blob并对其进行轻微修改 代码如下: create

我正在从事一个需要将现有Oracle Blob迁移到文件中的项目。要读取的环境是共享的Oracle 10gR2服务器。目前我有一个使用UTL_文件的脚本。然而,这个过程相当缓慢。提取25 GB的样本数据大约需要3小时。要移动的实际数据约为1 TB。我需要帮助/建议来调整此设置

以下是我的流程:

打开光标以获取blob ID和名称的列表 启动一个循环来遍历每个blob 使用BLOB2FILE提取blob,这是一个自定义存储过程,它从一个网站上获取blob并对其进行轻微修改 代码如下:

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;
日志\它是记录到表中的存储过程。应该不会有任何重大打击。 我尝试通过使用批量提取而不是普通提取来优化步骤1。然而,它没有产生任何显著的结果


有人能提出改进的想法吗?或者更好的是,提出一种更有效的方法

假设您的硬件足以处理远超过8 GB/小时的持续写入sDir的数据,并能够处理从blobTable读取的类似数据量,以及处理系统需要的任何其他I/O,最简单的选择可能是生成几个并行会话,每个会话都调用此过程。例如,如果您想并行运行三个作业,每个作业提取一个LOB,您可以执行类似的操作

DECLARE
  l_jobno INTEGER;
BEGIN
  dbms_job.submit( l_jobno, 'begin BLOB2File( 1, ''1.lob'', ''DIRECTORY'' ); end;', sysdate + interval '5' second );
  dbms_job.submit( l_jobno, 'begin BLOB2File( 2, ''2.lob'', ''DIRECTORY'' ); end;', sysdate + interval '5' second );
  dbms_job.submit( l_jobno, 'begin BLOB2File( 3, ''3.lob'', ''DIRECTORY'' ); end;', sysdate + interval '5' second );
  commit;
END;

实际上,您可能不希望每个BLOB都有一个单独的线程——您可能希望生成较少数量的作业,并为每个作业提供一系列lngBlobID值来处理。Oracle将在任何时间运行的作业数量受JOB_QUEUE_PROCESSES参数的限制,因此您可以提交数千个作业,只需让Oracle限制同时运行的作业数量。

感谢您的回复。这听起来很有可能,也很有帮助。我一定会试试这个。但是,由于数据库处于共享环境中,我希望提交大量作业不会导致服务器停机或降低其他用户的工作速度。@sammy-当然,同时运行的作业越多,消耗的I/O资源越多,其他用户可用的I/O资源也越少。这就是为什么我一开始就谈到在考虑了系统中其他用户的需求后,您的硬件有多少I/O带宽可供您利用。可以提交的作业数量有限制吗?我有大约500000个文件要提取。@sammy-我不认为可以提交的作业数量有限制。可同时运行的数量由作业队列进程控制。正如我所说,您可能不想提交500000个作业—您可能想提交50个作业,每个作业处理一组10000个LOB,或者500个作业,每个作业处理一组1000个LOB。您认为尝试使用SSD代替常规磁盘会显著降低速率吗?