Oracle - 使用过滤器选择排序行并导出到 csv:如何并行执行作业? start_id/end_id 是页偏移量,而不是列

问题描述 投票:0回答:1

我想过滤、排序并将数据从大表转储到 csv。甲骨文 12c。

  • unload
    会过滤但不会排序,但我想要稳定的排序,因为我需要将数据与其他来源的文件进行比较。而且它不会对输出文件进行分块。当然,如果有人知道如何在
    unload
    中做到这一点,请告诉。
  • dp
    unload
    相同,对吧?
  • 数据库中不存在
  • expdp
    ;没有安装?
  • 我正在探索如何使用
    DBMS_PARALLEL_EXECUTE
    包来做到这一点,但我找不到如何做。原因很简单:我想按页而不是按任何列对行进行分块。

我要执行的主要查询是:

select FIELD1, FIELD2
      from DATA
      where COMPANY_ID like :regex
      order by FIELD1   -- indexed and unique
      offset :start_id rows fetch next :page_size rows only;

我只想要 2 列。

我认为我不能使用

CREATE_CHUNKS_BY_NUMBER_COL
CREATE_CHUNKS_BY_ROWID
作为

  • 我认为过滤后没有连续的数字列。 CREATE_CHUNKS_BY_NUMBER_COL文档说:

此过程按指定列对表(与指定任务关联)进行分块。指定的列必须是 NUMBER 列。此过程获取列的 MIN 和 MAX 值,然后根据 chunk_size 均匀划分范围。

  • 并且该表不使用物理rowid。

第一个问题: 可以用PK吗? PK是

NUMBER
,而且是连续的;但通过
COMPANY_ID
过滤会使其不连续。例如,从 ID 0 到 500 我只需要 2 行,这会破坏工作,对吧?它会为我带来 2 还是 500?

第二个问题: 我正在关注 https://oracle-base.com/articles/11g/dbms_parallel_execute_11gR2#user_define_framework 但我不知道该块何时执行和计划。

我的代码:

create or replace procedure compare (
  dir varchar2, 
  regex varchar2, 
  start_id integer, 
  end_id integer, 
  page_size integer
) as
   CURSOR c_query is 
      select FIELD1, FIELD2
      from DATA
      where COMPANY_ID like regex
      order by FIELD1
      offset start_id rows fetch next page_size rows only;
  output   utl_file.file_type;
  filename varchar2(100);
begin
  filename := 'split_' || start_id || '_' || end_id || '.csv';
  output := utl_file.fopen ( dir, filename, 'w' );
  utl_file.put_line ( output, 'FIELD1,FIELD2' );
  
  for row in c_query loop
    utl_file.put_line ( output, row.FIELD1 || ',' || row.FIELD2 );
  end loop;
  utl_file.fclose ( output );
end compare;
/


create or replace procedure loop_comparison(
    l_task     VARCHAR2 := 'test_task',
    regex VARCHAR2 := '90%',
    page_size  NUMBER := 50,
    dir varchar2 := 'DATA_PUMP_DIR'
)
  as
    l_sql_stmt VARCHAR2(32767);
    l_sql_step_stmt VARCHAR2(32767);
    row_count  NUMBER;
    p_start    NUMBER := 0;
    p_end      NUMBER := 0;
BEGIN
  DBMS_PARALLEL_EXECUTE.create_task (task_name => l_task);

  select count(ID) into row_count from DATA where COMPANY_ID like regex;
  
  p_end := page_size;
  
  l_sql_stmt := 'BEGIN compare(''' || dir || ''',''' || regex || ''', :start_id, :end_id, ' || page_size || '); END;';
  WHILE p_start < row_count
  LOOP
    l_sql_step_stmt := 'select ' || p_start || ' as start_id, ' || p_end || ' as end_id from dual';
    DBMS_PARALLEL_EXECUTE.create_chunks_by_sql(task_name  => l_task,
                                                sql_stmt    => l_sql_step_stmt,
                                                by_rowid    => FALSE);

    DBMS_PARALLEL_EXECUTE.run_task(task_name      => l_task,
                                   sql_stmt       => l_sql_stmt,
                                   language_flag  => DBMS_SQL.NATIVE,
                                   parallel_level => 20,
                                   job_class      => 'test_task_class');
    DBMS_OUTPUT.put_line(
           TO_CHAR(SYSTIMESTAMP, 'yyyy-mm-dd hh24:mi:ss.ff')
        || '  '
        || DBMS_PARALLEL_EXECUTE.task_status(l_task)
    );
    p_start := p_start + page_size;
    p_end := p_end + page_size;
  END LOOP;
end loop_comparison;
/

exec loop_comparison
之后,我发现了这个:

SQL> select task_name, chunk_type, status from USER_PARALLEL_EXECUTE_TASKS;

   TASK_NAME    CHUNK_TYPE     STATUS
____________ _____________ __________
test_task    UNDECLARED    CREATED

SQL> select * from USER_PARALLEL_EXECUTE_CHUNKS;

no rows selected

我想它永远不会运行。

oracle parallel-processing
1个回答
0
投票

如果您正在执行 ORDER BY,那么无论如何您都将传递与您的条件匹配的整组行,因此不太可能从拆分中看到任何巨大的好处,除非主要成本是排序元素。

如果是这种情况,我会解决这个问题,例如提高 PGA 或拥有更快的 TEMP 表空间 IO。

'dp' 是数据泵,因此不适合 csv。

因为您按FIELD1排序,那么如果您知道FIELD1的一些上限/下限,那么您可以使用它进行分块/排序,因为根据定义,每个块将具有互斥的数据。您最终可能会得到不同的文件大小。

© www.soinside.com 2019 - 2024. All rights reserved.