Oracle 需要关于将格式化数据从表转储到给定限制的文件的建议吗

Oracle 需要关于将格式化数据从表转储到给定限制的文件的建议吗,oracle,plsql,oracle11g,Oracle,Plsql,Oracle11g,长话短说,我们有一个表,它是作为一个进程的结果创建的,在该进程结束时,我们需要将它提取到一个本地文件中,并在列之间使用一个类似于管道的分隔符(有时它们需要一个制表符或逗号,等等)。听起来很简单,但我们无法访问数据库的本地文件系统,无法通过UTL_文件调用写入目录对象或文件。该数据库实际上位于美国全国的一个供应商所有的系统上,并通过VPN访问 为了将输出输出到本地文件,在我们的Windows 7环境中,我们使用了一个.vbs程序(这是一个更大的流程的一部分)通过sqlplus调用一个.sql包装器

长话短说,我们有一个表,它是作为一个进程的结果创建的,在该进程结束时,我们需要将它提取到一个本地文件中,并在列之间使用一个类似于管道的分隔符(有时它们需要一个制表符或逗号,等等)。听起来很简单,但我们无法访问数据库的本地文件系统,无法通过UTL_文件调用写入目录对象或文件。该数据库实际上位于美国全国的一个供应商所有的系统上,并通过VPN访问

为了将输出输出到本地文件,在我们的Windows 7环境中,我们使用了一个.vbs程序(这是一个更大的流程的一部分)通过sqlplus调用一个.sql包装器脚本,该脚本只需将输出假脱机到本地文件,并调用使用DBMS_output.PUT_LINE()的过程,逐行游标(我知道,慢慢来),其输出格式化后由spool捕获到文件中。这是笨重的,但对于小表来说还可以,但现在我们有数百万行的表,性能编写是不可接受的

一定有更好的方法,因为像Toad这样的工具可以在相同的限制下立即将巨大的表转储到本地文件夹中,所以它们一定使用某种Oracle foo,我自己似乎无法发现如何做


任何想法都非常感谢

尝试在单独的文件中通过并行脚本卸载表,然后合并文件。只需要找出范围的关键

可选: 如果您有一个奢侈的分区,那么您可以通过单独的脚本并行卸载每个分区

我还很好奇,与select和for bulk COLLET相比,slow的速度有多慢,并制作了一个通过挂钟测量的快速基准测试(在SQL*Plus上设置计时)

  • 慢慢地,慢慢地,在00:01:04.98到达

    spool c:\temp\for.txt
    DECLARE
      i PLS_INTEGER:=0;
    BEGIN
      dbms_output.enable(1000000);
      FOR r IN (SELECT owner || '|' 
        || object_name || '|' 
        || object_type line FROM t_big) 
      LOOP
        i := i + 1;
        IF MOD(i, 1000)=0 THEN
          dbms_output.enable(1000000); --Reset buffer to avoid buffer overflow
        END IF;
        dbms_output.put_line(r.line);
      END LOOP;
    END;
    /
    spool OFF
    
  • 批量收集进近于00:01:05.08

       spool c:\temp\blk.txt
        DECLARE
          TYPE t IS TABLE OF VARCHAR2(4000);
          vt t;
          CURSOR c IS
            SELECT owner || '|' 
              || object_name || '|' 
              || object_type line FROM t_big;
        BEGIN
          OPEN c;
          LOOP
            FETCH c BULK COLLECT
              INTO vt LIMIT 1001;
                dbms_output.enable(1000000);
            FOR i IN 1 .. vt.count LOOP
              dbms_output.put_line(vt(i));
            END LOOP;
            EXIT WHEN vt.count=0;
          END LOOP;
        END;
        /
        spool OFF
    

  • 为什么要使用PL/SQL查询表,而不仅仅是直接的SQL查询?@Alex Poole如果我不清楚,我很抱歉。一个现有的过程在每次运行时都会截断然后构建一个新的表,执行一系列更新,等等,然后它所做的最后一件事就是通过游标读取行,用分隔符构建一个字符串并使用PUT_LINE(),wrapper.sql一次捕获并写入一行(groan)。我应该说,我正在尝试改进对文件部分的写入,可以肯定地将其移动到.sql包装器中。sqlplus有一个
    COLSEP
    SET
    命令,可以设置为分隔符。我将对此进行探讨。也许这可以设置,然后简单地从表中选择所有内容,在设置选项以抑制标题等之后。尽管如此,最终还是会出现大量空白,并且仍然需要确保日期等的格式符合预期;任何包含分隔符的字符串都可能导致问题,这需要更多的工作,但我通常会在查询中显式连接分隔符。@alex poole是的,我也是,这就是过程中的原始代码所做的。我正在想方设法加快将2100万行写入文件的速度-/有趣。谢谢你经历了这些麻烦。
    spool c:\temp\for.txt
    DECLARE
      i PLS_INTEGER:=0;
    BEGIN
      dbms_output.enable(1000000);
      FOR r IN (SELECT owner || '|' 
        || object_name || '|' 
        || object_type line FROM t_big) 
      LOOP
        i := i + 1;
        IF MOD(i, 1000)=0 THEN
          dbms_output.enable(1000000); --Reset buffer to avoid buffer overflow
        END IF;
        dbms_output.put_line(r.line);
      END LOOP;
    END;
    /
    spool OFF
    
       spool c:\temp\blk.txt
        DECLARE
          TYPE t IS TABLE OF VARCHAR2(4000);
          vt t;
          CURSOR c IS
            SELECT owner || '|' 
              || object_name || '|' 
              || object_type line FROM t_big;
        BEGIN
          OPEN c;
          LOOP
            FETCH c BULK COLLECT
              INTO vt LIMIT 1001;
                dbms_output.enable(1000000);
            FOR i IN 1 .. vt.count LOOP
              dbms_output.put_line(vt(i));
            END LOOP;
            EXIT WHEN vt.count=0;
          END LOOP;
        END;
        /
        spool OFF