从 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 管理特定于端口的 end-of -line 转换,但对于 CLOB,我们必须自己管理)。
特别感兴趣的是第 47 行的 DBMS_XSLPROCESSOR 调用,这是我们对目标平面文件的唯一写入操作。总的来说,我们可以看到这种技术在性能上与我们的缓冲 UTL_FILE 机制相似(CLOB 方法稍微快一些)。因此,我们有另一种写入数据的方法,但会产生与使用 CLOB 相关的额外成本(例如,临时表空间和缓冲区缓存)。如果要转储的数据量很大,那么这种方法可能会给我们的临时表空间带来太大的压力,并给其他用户带来问题(大型排序操作、散列连接、全局临时表等)。
因此在使用此方法时应小心。