pl/sql 函数调用了多少次?
假设您有以下更新:
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
在这种情况下,一些实验是有用的(这是在 10g 上进行的)。使用下面的查询,我们可以知道,使用相同参数(在本例中为无参数)的普通函数每次调用时都会执行:
这是因为 Oracle 假定函数不会一致地返回相同的值,除非您告诉否则。我们可以通过使用确定性关键字创建一个函数来做到这一点:
在第一个查询中使用此函数而不是 dbms_random 告诉我们该查询仅执行一次,尽管很多电话。但这只是澄清了
select
部分。如果我们在select
和where
子句中使用相同的确定性函数会怎样?我们可以使用以下查询进行测试:您可能需要运行几次才能看到我们的证明,但最终您会看到一个小于 0.5 的值列表。这为我们提供了证据,表明即使确定性函数也被执行两次:对于它出现的每个部分执行一次。作为替代方案,您可以按如下方式修改我们的确定性函数,然后运行后续查询,这将显示写入 < 的 2 行代码>DBMS_OUTPUT。
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:
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: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 theselect
section. What if we use the same deterministic function in both aselect
and awhere
clause. We can test that using the following query: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
.虽然我喜欢艾伦的回答来展示如何调查这个问题,但我认为真正要吸取的教训是,如果你可以避免这个问题,你就不应该依赖它的答案。
这是一篇有用的帖子关于 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.
对于 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.