pl/sql函数调用了多少次?

Flo*_*ita 8 sql oracle plsql oracle9i

假设您有以下更新:

Update table set col1 = func(col2)
where col1<>func(col2)
Run Code Online (Sandbox Code Playgroud)

FUNC函数为每个行计算两次,每行,或一次?

谢谢,

All*_*lan 11

这种情况下某些实验很有用(这是在10g上进行的).使用以下查询,我们可以告诉每次调用它们时,将使用相同的参数(在本例中为none)执行正常的函数:

select dbms_random.value() from all_tables
Run Code Online (Sandbox Code Playgroud)

这是因为Oracle假定函数不会一致地返回相同的值,除非您另有说明.我们可以通过使用deterministic关键字创建一个函数来做到这一点:

CREATE FUNCTION rand_det
   RETURN NUMBER
   DETERMINISTIC AS
BEGIN
   RETURN DBMS_RANDOM.VALUE ();
END;
Run Code Online (Sandbox Code Playgroud)

使用此函数而不是dbms_random第一个查询告诉我们,尽管进行了多次调用,查询仍然只执行一次.但这只是澄清了这一select部分.如果我们在a select和a where子句中使用相同的确定性函数,该怎么办?我们可以使用以下查询来测试:

SELECT rand_det
FROM   all_tables
WHERE  rand_det > .5;
Run Code Online (Sandbox Code Playgroud)

您可能需要多次运行才能看到我们的证明,但最终,您会看到一个小于0.5的值列表.这为我们提供了证据,即使确定性函数正在被执行两次:它出现的每个部分一次.作为替代,您可以如下修改我们的确定性函数,然后运行后续查询,这将显示写入的2行DBMS_OUTPUT.

CREATE OR REPLACE FUNCTION rand_det
   RETURN NUMBER
   DETERMINISTIC AS
BEGIN
   DBMS_OUTPUT.put_line ('Called!');
   RETURN DBMS_RANDOM.VALUE ();
END;

SELECT rand_det
FROM   all_tables;
Run Code Online (Sandbox Code Playgroud)


Dav*_*sta 10

虽然我喜欢艾伦的回答来展示如何对此进行调查,但我认为真正的教训是,如果你能避免,你不应该依赖这个问题的答案.

这是 Tom Kyte关于这个话题的一篇有用的文章("我已经写了数千次,你不能依赖多少次,或者SQL何时或者是否会调用你的函数.")即使在11g引入结果缓存之前,也有无法保证在处理SQL语句时调用函数的次数.它可能取决于执行计划,执行计划可能会随时间而变化.

如果您的关注点是性能并且您的功能是确定性的,则11g结果缓存可能就足够了 - 它不能保证对函数调用次数的特定限制,但应该显着减少冗余调用的数量.(参见@cularis回答中提供的链接.)

如果由于某种原因你确实想要确保对函数的两次调用是不同的,我认为你可以强制执行的唯一方法是向实际被忽略的函数添加第二个参数但是用于防止结果缓存或优化器看到调用是相同的.