在PL / SQL中使用参数或常量时,性能会有所不同

时间:2018-09-20 12:57:06

标签: oracle plsql query-performance

我遇到了性能问题。

第一个PL / SQL(大多数时间永远不会结束,并且OS数据库进程始终超过90%):

DECLARE 
  myId nvarchar2(10) := '0;WF21izb0';
BEGIN
  insert into MY_TABLE (select * from MY_VIEW where ID = myId);
END;

第二个PL / SQL(以50s成功结束):

BEGIN
  insert into MY_TABLE (select * from MY_VIEW where ID = '0;WF21izb0');
END;

select count(*) from MY_VIEW 

也是一个无休止的调用,此视图后面有很多表联接。

select count(*) from MY_VIEW where ID = '0;WF21izb0'

以50s结尾,计数为60000。

有人可以向我解释为什么我的第一个PL / SQL在50年代后没有完成的原因吗?使用静态字符串和声明的参数有什么区别?

2 个答案:

答案 0 :(得分:0)

归结为准备查询执行计划时数据库引擎对您的数据和查询的了解。

在查询中放置文字时,它是查询的一部分,负责准备计划的引擎知道该文字。可以考虑该字面值,并确定合适的执行计划,例如基于数据库数据统计信息(例如,该值很少)。

使用PL / SQL变量时,为其确定计划的实际查询是不同的。就像这样:

insert into MY_TABLE (select * from MY_VIEW where ID = :param)

如您所见,执行查询时,数据库引擎现在没有关于该值的信息,将使用该值。因此,针对这种情况的最佳计划是准备一些东西,这通常对大多数可能的值都有利(例如,查看数据库中哪些值最常与该位置匹配,即流行的值)。

如果您的数据不平衡,并且数据中的'0;WF21izb0'值很少(甚至不存在),则可以使用选择性索引来缩小需要处理的内容的范围,相对较短的时间执行计划的关键部分。但是,当您使用一个无处不在的值时,该计划将适得其反-索引的使用会适得其反。对于这种情况,更好的计划可能是全表扫描。可能与执行select count(*) from MY_VIEW时使用的相同。

如果您遇到不知道过滤值的情况,则必须分析视图代码,并尝试对其进行调整,以便它也可以有效地用于较少的“选择性”值。您可以尝试将一些优化程序提示应用于查询。您也可以退出使用视图,并尝试使用表格函数来试试运气,在该函数中,您可以将过滤谓词推送到查询的确切位置,从而可以最有效地使用它们。

修改
总之,请遵循问题注释中的建议,并检查您的执行计划和执行配置文件数据。您应该能够找到罪魁祸首。从那里开始,解决方案可能并不明显,但是您仍然知道您的数据和关系比我们更好。

答案 1 :(得分:0)

我正在检查一些痕迹,但是在阅读了APC的评论和Hilarion的回答后,我最终得到了以下解决方案:

declare sql_stmt VARCHAR2(200); id VARCHAR2(10) := '0;WF21izb0'; BEGIN sql_stmt := 'insert into MY_TABLE (select * from MY_VIEW where ID = :1)'; EXECUTE IMMEDIATE sql_stmt using id; END;

这是在50年代完成的,id现在可以是一个函数/过程参数。 感谢您的评论。