具有并行启用流水线功能的数据丢失

时间:2014-10-08 05:58:22

标签: oracle plsql

我有一个将数据加载到文件中的流水线功能。

以下是功能代码。

CREATE OR REPLACE FUNCTION DATA_UNLOAD
   ( p_source                 IN SYS_REFCURSOR,
      p_filename       IN VARCHAR2,
        p_directory      IN VARCHAR2
       ) RETURN dump_ntt PIPELINED PARALLEL_ENABLE (PARTITION p_source BY ANY)
AS
   TYPE row_ntt IS TABLE OF VARCHAR2(32767);
   v_rows       row_ntt;
   v_file       UTL_FILE.FILE_TYPE;
   v_buffer     VARCHAR2(32767);
   v_sid        VARCHAR(255);
   v_name       VARCHAR2(255);
   v_lines      PLS_INTEGER := 0;
   v_start_dttm TIMESTAMP WITH TIME ZONE:= SYSTIMESTAMP;
   v_end_dttm   TIMESTAMP WITH TIME ZONE;
   c_eol        CONSTANT VARCHAR2(1) := CHR(10);
   c_eollen     CONSTANT PLS_INTEGER := LENGTH(c_eol);
   c_maxline    CONSTANT PLS_INTEGER := 32767;   
BEGIN
  --v_sid := lpad(sys_context('USERENV', 'sid'), 10, '0');
  v_name:=p_filename;
  LOOP 
     if utl_file.is_open(v_file)
     then
        utl_file.fclose(v_file); 
     end if;
    v_file := UTL_FILE.FOPEN(p_directory, v_name, 'A', c_maxline);
    FETCH p_source BULK COLLECT INTO v_rows LIMIT 100;
  FOR i IN 1 .. v_rows.COUNT LOOP
     IF LENGTH(v_buffer) + c_eollen + LENGTH(v_rows(i)) <= c_maxline THEN
        v_buffer := v_buffer || c_eol || v_rows(i);
     ELSE
        IF v_buffer IS NOT NULL THEN
           UTL_FILE.PUT_LINE(v_file, v_buffer);
         END IF;
        v_buffer := v_rows(i);
      END IF;
    END LOOP;
    v_lines := v_lines + v_rows.COUNT;
    EXIT WHEN p_source%NOTFOUND;
  END LOOP;
  CLOSE p_source;   
   UTL_FILE.PUT_LINE(v_file, v_buffer);
   UTL_FILE.FCLOSE(v_file);
   v_end_dttm := SYSTIMESTAMP;
   --PIPE ROW (dump_ot(v_name, p_directory, v_lines, v_sid, v_start_dttm, v_end_dttm));
   --RETURN ;
END;

我用这种方式调用函数。

SELECT * from table(DATA_UNLOAD(
                         CURSOR(select /*+ PARALLEL */ a || b || c from sample_table),                                     
                        'sample.txt',
                         '99_DIR'));

我作为参数传递给函数的真实生活选择返回30000行,但是当我使用该函数将结果加载到文件中时,某些行会丢失。在使用PARALLEL提示执行期间,有24个并行会话,我不想减少它。我的猜测是问题在于并行执行,因为当我不使用PARALLEL提示时,没有数据丢失。如果没有删除提示,任何人都可以建议摆脱这个问题?

1 个答案:

答案 0 :(得分:1)

即使您正在使用追加模式创建sample.txt,您也会有24个并行会话。我总是通过将SID附加到您的变量来使用唯一的文件名:

SELECT sid INTO v_sid FROM v$mystat WHERE ROWNUM = 1;
v_name := p_filename || '_' || v_sid || '.dat';

根据并行会话的数量,您应该使用格式为sample_ nnnn .txt的1到多个文件,其中 nnnn 是SID编号。