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

发布于 2024-11-25 13:22:47 字数 161 浏览 3 评论 0原文

假设您有以下更新:

Update table set col1 = func(col2)
where col1<>func(col2)

func 函数对每行计算两次,还是每行计算一次?

谢谢,

Assume you have the following update:

Update table set col1 = func(col2)
where col1<>func(col2)

The func function is evaluated two times for every row, or once for every row?

Thanks,

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

千紇 2024-12-02 13:22:47

在这种情况下,一些实验是有用的(这是在 10g 上进行的)。使用下面的查询,我们可以知道,使用相同参数(在本例中为无参数)的普通函数每次调用时都会执行:

select dbms_random.value() from all_tables

这是因为 Oracle 假定函数不会一致地返回相同的值,除非您告诉否则。我们可以通过使用确定性关键字创建一个函数来做到这一点:

CREATE FUNCTION rand_det
   RETURN NUMBER
   DETERMINISTIC AS
BEGIN
   RETURN DBMS_RANDOM.VALUE ();
END;

在第一个查询中使用此函数而不是 dbms_random 告诉我们该查询仅执行一次,尽管很多电话。但这只是澄清了 select 部分。如果我们在 selectwhere 子句中使用相同的确定性函数会怎样?我们可以使用以下查询进行测试:

SELECT rand_det
FROM   all_tables
WHERE  rand_det > .5;

您可能需要运行几次才能看到我们的证明,但最终您会看到一个小于 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;

This is the kind of situation where some experimentation is useful (this was conducted on 10g). Using the following query, we can tell that normal functions, using the same parameters (in this case, none) will be executed each time they are called:

select dbms_random.value() from all_tables

This is because Oracle assumes that a function will not return the same value consistently unless you tell it otherwise. We can do that by creating a function using the deterministic keyword:

CREATE FUNCTION rand_det
   RETURN NUMBER
   DETERMINISTIC AS
BEGIN
   RETURN DBMS_RANDOM.VALUE ();
END;

Using this function instead of dbms_random in the first query tells us that the query is being executed only once, despite the many calls. But this only clarifies the select section. What if we use the same deterministic function in both a select and a where clause. We can test that using the following query:

SELECT rand_det
FROM   all_tables
WHERE  rand_det > .5;

You may have to run this several times to see our proof, but, eventually, you'll see a list of values less than 0.5. This provides us with evidence that even the deterministic function is being executed twice: once for each section it appears in. As an alternative, you can modify our deterministic function as follows, then run the subsequent query, which will reveal 2 lines written to 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;
千紇 2024-12-02 13:22:47

虽然我喜欢艾伦的回答来展示如何调查这个问题,但我认为真正要吸取的教训是,如果你可以避免这个问题,你就不应该依赖它的答案。

这是一篇有用的帖子关于 Tom Kyte 的主题(“我已经写了数千次,你不能依赖 SQL 会调用你的次数、时间或是否)函数。”)即使在 11g 引入结果缓存之前,也无法保证在处理 SQL 语句时函数将被调用多少次。它可能取决于执行计划,而执行计划可能会随着时间的推移而改变。

如果您关心的是性能并且您的函数是确定性的,那么 11g 结果缓存可能就足够了——它不能保证函数调用次数的特定限制,但应该会显着减少冗余调用的次数。 (请参阅 @ularis 答案中提供的链接。)

如果出于某种原因您实际上想确保对函数的两次调用是不同的,我认为您可以强制执行此操作的唯一方法是向函数添加第二个参数,即实际上被忽略,但用于防止结果缓存或优化器将调用视为相同。

While I like Allan's answer for showing how to investigate this, I think the real lesson to take away is that you shouldn't rely on the answer to this question if you can avoid it.

Here's a useful post on the topic from Tom Kyte ("I've written thousands of times that you cannot rely on how many times or when or if SQL will call your function.") Even prior to 11g introducing the result cache, there are no guarantees about how many times a function will be called in processing a SQL statement. It can depend on the execution plan, which can change over time.

If your concern is performance and your function is deterministic, the 11g result cache is probably sufficient -- it won't guarantee a specific limit on the number of calls to the function, but should reduce the number of redundant calls significantly. (See link provided in @cularis answer.)

If for some reason you actually want to ensure that the two calls to the functions are distinct, I think the only way you could force that would be to add a second parameter to the function that is actually ignored but serves to prevent the result cache or optimizer from seeing the calls as identical.

谁的年少不轻狂 2024-12-02 13:22:47

对于 11g,每次出现新的 col2 都会调用一次。对于下一次调用,如果启用了缓存,则使用缓存结果。

For 11g, it will be called once for every new occurence of col2. For the next calls, a cached result is used if caching is enabled.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文