PLSQL 循环需要大量时间来执行
Posted
技术标签:
【中文标题】PLSQL 循环需要大量时间来执行【英文标题】:PLSQL Loop taking lot of time to execute 【发布时间】:2017-01-04 02:13:55 【问题描述】:我有一个 Oracle 程序正在更新低于 10,000 条记录。如果我运行正常的 SQL 语句,它会在几秒(30)内立即返回结果。 程序循环中的相同语句将无限循环。
我的循环语句如下。 注意:data FIELD 数据类型是 clob 而不是 varchar2。
声明:
select
'LB_COPY_CHANGE-'||8 LAST_MODIFIED_BY,
rec.COR_ID_old,
rec.COR_ID_NEW,
replace(replace(replace(a.data,'''id'':'||rec.COR_ID_OLD||',','''id'':'||rec.COR_ID_NEW||','),''id':'||rec.COR_ID_OLD||',',''id':'||rec.COR_ID_NEW||','),'''id'':'||rec.COR_ID_OLD||',','''id'':'||rec.COR_ID_NEW||',') as data
from KPI_MET_FIELD_DATA a, CUSTOM_TEMP_TABLE_SESSION_1 rec
where A.cmf_fk_id in (145,146,147)
and TYPE_LB in (14,15,16)
and a.KDB_FK_ID in (
select distinct km.KDB_FK_ID
from KPI_MET_FIELD_DATA km , KPI_DET_BASE kp, KPI_REL_KPI_SCORECARD ksc, STR_DET_EMP_SCORECARD sc
where ksc.SDE_FK_ID=sc.SDE_PK_ID
and km.KDB_FK_ID = ksc.KDB_KPI_FK_ID
and km.is_deleted=0
and kp.kdb_pk_id = km.KDB_FK_ID
and kp.is_deleted=0
and km.cmf_fk_id in (145,146,147)
and sc.sdp_fk_id = 8)
and a.is_deleted=0
and (a.data like '%'||rec.COR_ID_OLD||'%');
FOR rec in (SELECT * FROM CUSTOM_TEMP_TABLE_SESSION where TYPE_LB in (14,15,16)) LOOP
update KPI_MET_FIELD_DATA
set LAST_MODIFIED_BY='LB_COPY_CHANGE-'||p2 ,
data = replace(replace(replace(data,'''id'':'||rec.COR_ID_OLD||',','''id'':'||rec.COR_ID_NEW||','),''id':'||rec.COR_ID_OLD||',',''id':'||rec.COR_ID_NEW||','),'''id'':'||rec.COR_ID_OLD||',','''id'':'||rec.COR_ID_NEW||',')
where cmf_fk_id in (145,146,147)
and KDB_FK_ID in (
select distinct km.KDB_FK_ID
from KPI_MET_FIELD_DATA km , KPI_DET_BASE kp, KPI_REL_KPI_SCORECARD ksc, STR_DET_EMP_SCORECARD sc
where ksc.SDE_FK_ID=sc.SDE_PK_ID
and km.KDB_FK_ID = ksc.KDB_KPI_FK_ID
and km.is_deleted=0
and kp.kdb_pk_id = km.KDB_FK_ID
and kp.is_deleted=0
and km.cmf_fk_id in (145,146,147)
and sc.sdp_fk_id = p2)
and is_deleted=0 ;
【问题讨论】:
你是什么意思,“正常的 SQL 语句?”如果不提供更多细节,比如解释计划,可能有很多可能的原因。需要更多细节。为什么你甚至需要一个循环? 相同结果集的选择语句: 是否有任何理由在循环中多次更新相同的记录?在 WHERE 语句中,您拥有在 LOOP 语句期间未更改的过滤器。这意味着您一次又一次地更新同一条记录 选择不同于更新,它做了两件非常不同的事情。对更新运行解释计划。 在 FOR 循环的更新中,您缺少一个 where 过滤器行“和 (a.data like '%'||rec.COR_ID_OLD||'%')”,这会导致更新运行FOR LOOP 游标返回的每条记录。因此 UPDATE 使用 FOR LOOP 光标进行笛卡尔积,而在 select 中两者之间有一个 JOIN。 【参考方案1】:您的代码有几个弱点。
WHERE KDB_FK_ID in (select distinct ...
没有任何意义。无需为 IN ()
子句创建 DISTINCT
。
使用 ANSI 连接语法代替旧的 Oracle 连接语法,这样更不容易出错
但主要区别在于,您的循环不包含连接条件(a.data like '%'||rec.COR_ID_OLD||'%')
,即您为CUSTOM_TEMP_TABLE_SESSION where TYPE_LB in (14,15,16)
中的每一行一次又一次地更新整个表KPI_MET_FIELD_DATA
【讨论】:
是的,先生,同意您的观点,但是否有任何替代解决方案,因为已经相应地改变了您在以前的 cmets 中发现的内容。但仍然是相同的结果。谢谢 再一次,这些语句在做不同的事情 - 您如何期望它们在同一时间执行?以上是关于PLSQL 循环需要大量时间来执行的主要内容,如果未能解决你的问题,请参考以下文章