在我的PL / SQL函数中,我将输出一个1400万行的csv文件。每行将有3个字段。
我担心I / O进程运行时间。我可以为这个批处理创建和输出多个csv文件。我不想逐行输出。
写文件的最佳和快捷方式是什么。例如,获取数据然后填入记录。然后写下文件。
感谢。
答案 0 :(得分:0)
从Oracle 10g开始,可以使用DBMS_XSLPROCESSOR.CLOB2FILE过程将CLOB写入一个文件,只需一次调用。在下面的示例中,我们将使用我们的数据准备临时CLOB,而不是使用UTL_FILE编写它。当所有源数据都添加到CLOB后,我们将在一次调用中将其写入平面文件。
SQL> DECLARE
2
3 v_file CLOB;
4 v_buffer VARCHAR2(32767);
5 v_name VARCHAR2(128) := 'clob2file_buffered.txt';
6 v_lines PLS_INTEGER := 0;
7 v_eol VARCHAR2(2);
8 v_eollen PLS_INTEGER;
9 c_maxline CONSTANT PLS_INTEGER := 32767;
10
11 BEGIN
12
13 v_eol := CASE
14 WHEN DBMS_UTILITY.PORT_STRING LIKE 'IBMPC%'
15 THEN CHR(13)||CHR(10)
16 ELSE CHR(10)
17 END;
18 v_eollen := LENGTH(v_eol);
19
20 DBMS_LOB.CREATETEMPORARY(v_file, TRUE);
21
22 FOR r IN (SELECT x || ',' || y || ',' || z AS csv
23 FROM source_data)
24 LOOP
25
26 IF LENGTH(v_buffer) + v_eollen + LENGTH(r.csv) <= c_maxline THEN
27 v_buffer := v_buffer || v_eol || r.csv;
28 ELSE
29 IF v_buffer IS NOT NULL THEN
30 DBMS_LOB.WRITEAPPEND(
31 v_file, LENGTH(v_buffer) + v_eollen, v_buffer || v_eol
32 );
33 END IF;
34 v_buffer := r.csv;
35 END IF;
36
37 v_lines := v_lines + 1;
38
39 END LOOP;
40
41 IF LENGTH(v_buffer) > 0 THEN
42 DBMS_LOB.WRITEAPPEND(
43 v_file, LENGTH(v_buffer) + v_eollen, v_buffer || v_eol
44 );
45 END IF;
46
47 DBMS_XSLPROCESSOR.CLOB2FILE(v_file, 'DUMP_DIR', v_name);
48 DBMS_LOB.FREETEMPORARY(v_file);
49
50 DBMS_OUTPUT.PUT_LINE('File='||v_name||'; Lines='||v_lines);
51
52 END;
53 /
文件= clob2file_buffered.txt;行= 1000000
PL / SQL程序已成功完成。
经过时间:00:00:28.65
CLOB特定的代码在上面突出显示并且不言自明(可能除了第13-17行的行尾字符分配外,对于Windows来说是不同的.UTL_FILE管理端口特定的结尾 - 为我们提供线路转换,但对于CLOB,我们必须自己管理。)
特别感兴趣的是第47行的DBMS_XSLPROCESSOR调用,它是我们对目标平面文件的唯一写操作。我们总体上可以看到这种技术在性能上与我们的缓冲UTL_FILE机制相似(CLOB方法稍微快一些)。因此,我们有另一种写入数据的方法,但是使用CLOB会产生额外的成本(例如,临时表空间和缓冲区缓存)。如果要转储的数据量很大,则此方法可能会对我们的临时表空间施加太大压力,并导致其他用户出现问题(大型排序操作,散列连接,全局临时表等)。
使用此方法时应小心。