需要有关在给定限制下从表到文件​​转储格式化数据的建议

时间:2015-12-29 19:27:05

标签: oracle plsql oracle11g

简而言之,我们有一个表是由一个进程创建的,在该进程结束时我们需要将它提取到一个本地文件,其中的分隔符就像列之间的管道(有时它们需要一个TAB或逗号,无论如何)。听起来很简单,但是我们无法访问数据库的本地文件系统,也无法通过UTL_FILE调用写入目录对象或文件。该数据库实际上位于全国各地的供应商拥有的系统上,并通过VPN访问。

为了在这里输出到本地文件,从我们的Windows 7环境开始,我们一直在使用.vbs程序(这是一个更大的流程的一部分)通过sqlplus调用.sql包装器脚本,只是假脱机输出到一个本地文件并调用逐行游标使用DBMS_OUTPUT.PUT_LINE()的过程(我知道,慢速慢),其输出格式化然后由spool捕获到文件。这很笨重,但对于小型表来说没问题,但现在我们有几百万行表,性能写入是不可接受的。

必须有一个更好的方法,因为像Toad这样的工具可以在相同的限制下立即将巨大的表转储到本地文件夹,因此他们必须使用某些我似乎无法发现的Oracle-foo做自己。

非常感谢任何想法!

1 个答案:

答案 0 :(得分:0)

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

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

我也很好奇,与选择和批量收集相比,慢得多慢,并通过挂钟进行快速基准测量(在SQL * Plus上设置时间)

akra@XE> DROP TABLE t_big;

Table dropped.

akra@XE> CREATE TABLE t_big TABLESPACE USERS AS
  2  SELECT *
  3    FROM (SELECT * FROM all_objects WHERE rownum <= 200)
  4    JOIN (SELECT 1 FROM dual CONNECT BY LEVEL <= 1000)
  5      ON 1 = 1;

Table created.

akra@XE>
akra@XE> SELECT COUNT(*) FROM t_big;

  COUNT(*)
----------
    200000
  1. SELECT在00:00:39.36

    中在我的机器上创建了一个文件
    SET feedback OFF
    SET timing ON
    SET TERMOUT OFF   
    spool c:\temp\sel.txt
    SELECT Owner||'|'||object_name||'|'||object_type line FROM t_big;
    spool OFF
    
  2. 在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
    
  3. 批量收集方法花了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