我有一些PL / SQL,它可以运行并“运行”,我想知道是否可以以更有效的方式编写它?
在某些背景下,元数据表包含可用于构造在远程数据库上执行的查询的信息。 这被传递到“ c1”。 “ driver_table”用于限制返回的数据,我们不需要所有数据,因此查询中存在一些条件。 例如,它可以是LIMITER_USER.TABLE1,mand_join是一个连接条件,例如A.ID = B.ID add_joins是where子句。例如。 B.DTE> = '01 -DEC-2014' 因此,最终,PL / SQL在循环中构造许多SQL并将其输出到输出中。
declare
v_sql_c1 pls_integer;
l_dblink varchar2(100) := 'DB1';
begin
for c1 in (select /*+parallel*/ * from meta_data_tbl where add_joins is not null)
loop
execute immediate' select /*+parallel*/ count(*) from '||c1.schema||'.'||c1.table|| '@' ||l_dblink ||' b '
||','||
c1.driver_table
|| '@' ||l_dblink ||' a '
||' where '||
c1.mand_join
||' and '||
c1.add_joins
into v_sql_c1;
dbms_output.put_line(v_sql_c1);
end loop;
end;
/
我希望输出尽可能地高效(如果还没有的话)。目前需要十二分钟才能完成
答案 0 :(得分:1)
您可能希望使用并行管道功能来启用并发和并行性。
术语“并发”和“并行性”通常是同义词,但在Oracle中有时具有不同的含义。并发是指同时运行多个SQL语句或PL / SQL块,而并行是指一个SQL语句具有多个线程的运行。
您当前的程序使用并行性来获取游标数据,但这不会使游标FOR循环在多个线程中运行。由于您正在使用数据库链接,因此我假设这些语句将在许多数据库上运行,因此您可以通过在多个数据库上同时运行它们来节省时间。
并行流水线函数并行运行输入游标,并对结果进行分区并在多个线程中运行它们。 (您可以使用DBMS_SCHEDULER实现相同的操作,但是该解决方案需要更多的管理代码。)
--Create parallel pipelined function.
create or replace function parallel_pipe(p_cursor sys_refcursor)
return sys.odcinumberlist pipelined
parallel_enable(partition p_cursor by any) is
v_meta_data_tbl meta_data_tbl%rowtype;
v_sql varchar2(32767);
v_count number;
begin
loop
fetch p_cursor into v_meta_data_tbl;
exit when p_cursor%notfound;
v_sql := 'select /*+ parallel */ count(*) from '||
v_meta_data_tbl.schema||'.'||v_meta_data_tbl.table_name;
execute immediate v_sql into v_count;
pipe row(v_count);
end loop;
end;
/
--Call the function.
select column_value row_count
from table(parallel_pipe(cursor(select /*+ parallel */ * from meta_data_tbl)));
我没有重新创建整个表并加入。我只是使用了足够小的模式来说明原理:
create table meta_data_tbl(schema varchar2(128), table_name varchar2(128));
insert into meta_data_tbl select 'SYS', 'DUAL' from dual connect by level <= 100;
commit;
在合并并发和并行性时要小心。上述解决方案可能会使您的服务器工作难度提高几个数量级。您应该尝试使用不同的组合-尝试仅运行并发,或者并发或少量并行运行,等等。