我想过滤、排序并将数据从大表转储到 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
作为
此过程按指定列对表(与指定任务关联)进行分块。指定的列必须是 NUMBER 列。此过程获取列的 MIN 和 MAX 值,然后根据 chunk_size 均匀划分范围。
第一个问题: 可以用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
我想它永远不会运行。
如果您正在执行 ORDER BY,那么无论如何您都将传递与您的条件匹配的整组行,因此不太可能从拆分中看到任何巨大的好处,除非主要成本是排序元素。
如果是这种情况,我会解决这个问题,例如提高 PGA 或拥有更快的 TEMP 表空间 IO。
'dp' 是数据泵,因此不适合 csv。
因为您按FIELD1排序,那么如果您知道FIELD1的一些上限/下限,那么您可以使用它进行分块/排序,因为根据定义,每个块将具有互斥的数据。您最终可能会得到不同的文件大小。