使用批量收集提高plsql的性能
我使用批量收集来提高执行时间。当我不使用批量收集时,它会在4分钟内执行。 但当我使用批量收集时,并没有输出,控制台中也不会显示错误消息。我可以看到创建了一个空白的spool文件。 请让我知道,如果我使用批量收集不正确,我们也可以在select语句中使用此子句并限制吗? 表由最多100万条记录组成使用批量收集提高plsql的性能,sql,oracle,plsql,Sql,Oracle,Plsql,我使用批量收集来提高执行时间。当我不使用批量收集时,它会在4分钟内执行。 但当我使用批量收集时,并没有输出,控制台中也不会显示错误消息。我可以看到创建了一个空白的spool文件。 请让我知道,如果我使用批量收集不正确,我们也可以在select语句中使用此子句并限制吗? 表由最多100万条记录组成 SET SERVEROUTPUT ON FORMAT WRAPPED SET VERIFY OFF SET FEEDBACK OFF SET TERMOUT OFF SPOOL C:\Temp\spo
SET SERVEROUTPUT ON FORMAT WRAPPED
SET VERIFY OFF
SET FEEDBACK OFF
SET TERMOUT OFF
SPOOL C:\Temp\spool_1.txt
DECLARE
cursor c2 is (
select count(distinct e.cdb_pref_event_id)
,e.supp_cd
from (select distinct eh.cdb_customer_id cdb_customer_id
,eh.cdb_pref_event_id cdb_pref_event_id
,eh.supp_cd supp_cd
from (select *
from cdb_stg.cpm_pref_event_stg_arc
where trunc(load_date) = trunc(sysdate - 1)) eh
Left outer join cdb_admin.cpm_pref_result er on (eh.cdb_customer_id =
er.cdb_customer_id and
eh.cdb_pref_event_id =
er.cdb_pref_event_id)
where er.cdb_pref_event_id is null
and er.cdb_customer_id is null) r
join cdb_admin.cpm_pref_event_exception e on (r.cdb_customer_id =
e.cdb_customer_id and
r.cdb_pref_event_id =
e.cdb_pref_event_id)
group by e.supp_cd);
TYPE totalprefresults is table of NUMBER(20);
TYPE supcd_1 is table of cdb_admin.cpm_pref_event_stg.supp_cd%TYPE;
total_prefresults totalprefresults;
supcd1 supcd_1;
--Total_prefresults NUMBER(20);
--SUPCD1 CDB_ADMIN.CPM_PREF_EVENT_STG.supp_cd%TYPE;
profile_counts NUMBER(20);
iter Integer := 0;
BEGIN
select count(distinct cdb_customer_id)
into profile_counts
from cdb_admin.cpm_pref_event_exception h
where cdb_customer_id in
(Select distinct e.cdb_customer_id
from (Select distinct eh.cdb_customer_id cdb_customer_id
,eh.cdb_pref_event_id cdb_pref_event_id
,eh.supp_cd supp_cd
from (select *
from cdb_stg.cpm_pref_event_stg_arc
where trunc(load_date) = trunc(sysdate - 1)) eh
Left outer join cdb_admin.cpm_pref_result er on (eh.cdb_customer_id =
er.cdb_customer_id and
eh.cdb_pref_event_id =
er.cdb_pref_event_id)
where er.cdb_pref_event_id is null
and er.cdb_customer_id is null) r
join cdb_admin.cpm_pref_event_exception e on (r.cdb_customer_id =
e.cdb_customer_id and
r.cdb_pref_event_id =
e.cdb_pref_event_id)
where e.supp_cd = 'PROFILE-NOT-FOUND')
and h.supp_cd != 'PROFILE-NOT-FOUND';
dbms_output.put_line('TOTAL EVENTS VALIDATION');
dbms_output.put_line('-------------------------------------------------------------');
dbms_output.put_line('');
dbms_output.put_line(rpad('Pref_Counts', 25) || rpad('Supp_CD', 25));
OPEN c2;
LOOP
FETCH c2 BULK COLLECT
INTO total_prefresults
,supcd1 limit 100;
EXIT WHEN c2%NOTFOUND;
dbms_output.put_line(rpad(total_prefresults, 25) || rpad(supcd1, 25));
IF (supcd1 = 'PROFILE-NOT-FOUND')
then
dbms_output.put_line('');
dbms_output.put_line('Profile not found records count : ' ||
total_prefresults);
dbms_output.put_line(profile_counts ||
' : counts moved to other exceptions ');
dbms_output.put_line((total_prefresults - profile_counts) ||
' : are still in Profile_not_found exception');
END IF;
iter := iter + 1;
END LOOP;
CLOSE c2;
dbms_output.put_line('');
dbms_output.put_line('Number of missing Records: ' || iter);
END;
/
SPOOL OFF
我已经从
openc2开始重新编写了您的代码代码>至<代码>关闭c2代码>
应执行批量收集
以仅存储收集中的所有数据一次(一次性),然后可使用FOR loop
中的索引(即在以下情况下为i)使用此收集,如下所示:
OPEN C2;
FETCH C2 BULK COLLECT INTO
TOTAL_PREFRESULTS,
SUPCD1;
--EXIT WHEN C2%NOTFOUND;
CLOSE C2;
-- To list down all the values before processing the logic
FOR I IN TOTAL_PREFRESULTS.FIRST..TOTAL_PREFRESULTS.LAST LOOP
DBMS_OUTPUT.PUT_LINE(RPAD(TOTAL_PREFRESULTS(I), 25)
|| RPAD(SUPCD1(I), 25));
END LOOP;
FOR I IN TOTAL_PREFRESULTS.FIRST..TOTAL_PREFRESULTS.LAST LOOP
IF ( SUPCD1(I) = 'PROFILE-NOT-FOUND' ) THEN
DBMS_OUTPUT.PUT_LINE('');
DBMS_OUTPUT.PUT_LINE('Profile not found records count : ' || TOTAL_PREFRESULTS(I));
DBMS_OUTPUT.PUT_LINE(PROFILE_COUNTS || ' : counts moved to other exceptions ');
DBMS_OUTPUT.PUT_LINE((TOTAL_PREFRESULTS(I) - PROFILE_COUNTS)
|| ' : are still in Profile_not_found exception');
END IF;
ITER := ITER + 1;
END LOOP;
在代码中替换上述代码段并尝试执行
参考
干杯 我已经从打开c2开始重新编写了您的代码代码>至<代码>关闭c2代码>
应执行批量收集
以仅存储收集中的所有数据一次(一次性),然后可使用FOR loop
中的索引(即在以下情况下为i)使用此收集,如下所示:
OPEN C2;
FETCH C2 BULK COLLECT INTO
TOTAL_PREFRESULTS,
SUPCD1;
--EXIT WHEN C2%NOTFOUND;
CLOSE C2;
-- To list down all the values before processing the logic
FOR I IN TOTAL_PREFRESULTS.FIRST..TOTAL_PREFRESULTS.LAST LOOP
DBMS_OUTPUT.PUT_LINE(RPAD(TOTAL_PREFRESULTS(I), 25)
|| RPAD(SUPCD1(I), 25));
END LOOP;
FOR I IN TOTAL_PREFRESULTS.FIRST..TOTAL_PREFRESULTS.LAST LOOP
IF ( SUPCD1(I) = 'PROFILE-NOT-FOUND' ) THEN
DBMS_OUTPUT.PUT_LINE('');
DBMS_OUTPUT.PUT_LINE('Profile not found records count : ' || TOTAL_PREFRESULTS(I));
DBMS_OUTPUT.PUT_LINE(PROFILE_COUNTS || ' : counts moved to other exceptions ');
DBMS_OUTPUT.PUT_LINE((TOTAL_PREFRESULTS(I) - PROFILE_COUNTS)
|| ' : are still in Profile_not_found exception');
END IF;
ITER := ITER + 1;
END LOOP;
在代码中替换上述代码段并尝试执行
参考
干杯 我认为瓶颈是这样的条件:其中trunc(load_date)=trunc(sysdate-1)
您在trunc(加载日期)
上有索引吗?根据trunc(load\u date)
创建基于函数的索引,或者如果您已经在load\u date
上创建了索引,请重试
WHERE load_date >= trunc(sysdate - 1) AND load_date < trunc(sysdate)
其中加载日期>=trunc(sysdate-1)和加载日期
还要检查您的查询是否真的需要distinct
。如果可能,请删除它们。我认为瓶颈是这样的情况:其中trunc(加载日期)=trunc(sysdate-1)
您在trunc(加载日期)
上有索引吗?根据trunc(load\u date)
创建基于函数的索引,或者如果您已经在load\u date
上创建了索引,请重试
WHERE load_date >= trunc(sysdate - 1) AND load_date < trunc(sysdate)
其中加载日期>=trunc(sysdate-1)和加载日期
还要检查您的查询是否真的需要distinct
。如果可能,请删除它们。批量收集可以提供可观的性能增益。然而,其中也有一些问题
首先,%notfound的含义不同。
在标准游标上%notfound表示所有行都已提取,没有其他行。对于批量收集,此更改为“没有足够的行达到指定的限制(如果存在)”。
这并不意味着没有获取行,只是没有达到指定的限制。例如,如果您的限制为100,并且仅检索到50次提取,则%notfound将返回True。这就是参考指南失败的地方。
第二个是没有limit子句的情况:游标中的所有行都返回到共享内存(PGA?)中。那有什么问题呢。
如果有100行或1000行,则很可能是k,但假设有100000行或1M行,它们仍然全部加载到内存中。最后(至少现在)当使用limit子句时,整个Fetch+进程本身必须包含在一个循环中,或者您只处理第一次Fetch,即只处理指定的限制行数,而不管实际存在多少行。参考指南失败的另一点。
以下骨架适用于上述情况
declare
max_bulk_rows constant integer := 1000; -- define the max number of rows for each fetch ...
cursor c_bulk is(
Select ... ;
type bulk_row_t is table of c_bulk%rowtype;
bulk_row bulk_row_t;
Begin
open c_bulk;
loop
fetch c_bulk -- fill buffer
bulk collect into bulk_row
limit max_bulk_row;
for i in bulk_row.first .. bulk_row.last -- process each row in buffer
loop
"process individual row here"
end loop;
foreach ... -- bulk output of rows here is needed.
exit when bulk_row.count < max_bulk_row; -- exit process loop if all rows processed
end loop ; -- loop back and fetch next buffer if needed
close c_bulk;
...
end;
声明
最大批量行常量整数:=1000;--定义每次提取的最大行数。。。
游标c_批量为(
选择;
类型bulk\u row\t是c\u bulk%rowtype的表;
大排大排;
开始
开放式散装;
环
获取c_批量--填充缓冲区
批量收集到批量_行
限制最大批量行;
对于bulk\u row.first..bulk\u row.last中的i——处理缓冲区中的每一行
环
“在此处处理单个行”
端环;
foreach…--这里需要大量输出行。
当bulk_row.count
批量收集可以提供可观的性能提升。但是,其中涉及到一些问题。
首先,%notfound的含义不同。
在标准游标上%notfound表示已提取所有行,并且没有其他行。对于批量收集,此更改为“没有足够的行达到指定的限制(如果存在)”。
这并不意味着没有获取任何行,只是未达到指定的限制。例如,如果限制为100,并且仅检索到50,则%notfound将返回True。这就是引用的指南失败的原因。
第二个问题是在没有limit子句的情况下会发生什么:游标中的所有行都返回到共享内存(PGA?)中。那么这有什么问题呢。
如果有100行或1000行,那么很可能是k,但假设有100000行或1M行,它们仍然全部加载到内存中当使用limit子句时,整个Fetch+进程本身必须包含在一个循环中,或者您只处理第一次Fetch(仅表示指定的限制行数),而不管实际存在多少行。参考指南失败的另一点。
以下骨架适用于上述情况
declare
max_bulk_rows constant integer := 1000; -- define the max number of rows for each fetch ...
cursor c_bulk is(
Select ... ;
type bulk_row_t is table of c_bulk%rowtype;
bulk_row bulk_row_t;
Begin
open c_bulk;
loop
fetch c_bulk -- fill buffer
bulk collect into bulk_row
limit max_bulk_row;
for i in bulk_row.first .. bulk_row.last -- process each row in buffer
loop
"process individual row here"
end loop;
foreach ... -- bulk output of rows here is needed.
exit when bulk_row.count < max_bulk_row; -- exit process loop if all rows processed
end loop ; -- loop back and fetch next buffer if needed
close c_bulk;
...
end;
声明
max_bulk_rows常量整数:=1000;--定义每次提取的最大行数。。。
游标c_批量为(
选择;
类型bulk\u row\t是c\u bulk%rowtype的表;
大排大排;
开始
开放式散装;
环
取c_块