简而言之,我们有一个表是由一个进程创建的,在该进程结束时我们需要将它提取到一个本地文件,其中的分隔符就像列之间的管道(有时它们需要一个TAB或逗号,无论如何)。听起来很简单,但是我们无法访问数据库的本地文件系统,也无法通过UTL_FILE调用写入目录对象或文件。该数据库实际上位于全国各地的供应商拥有的系统上,并通过VPN访问。
为了在这里输出到本地文件,从我们的Windows 7环境开始,我们一直在使用.vbs程序(这是一个更大的流程的一部分)通过sqlplus调用.sql包装器脚本,只是假脱机输出到一个本地文件并调用逐行游标使用DBMS_OUTPUT.PUT_LINE()的过程(我知道,慢速慢),其输出格式化然后由spool捕获到文件。这很笨重,但对于小型表来说没问题,但现在我们有几百万行表,性能写入是不可接受的。
必须有一个更好的方法,因为像Toad这样的工具可以在相同的限制下立即将巨大的表转储到本地文件夹,因此他们必须使用某些我似乎无法发现的Oracle-foo做自己。
非常感谢任何想法!
答案 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
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
在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