Oracle 如何处理 SQL 中的存储函数调用?
伙计们。假设我有一个查询:
select t.value, my_stored_function(t.value)
from my_table t
where my_stored_function(t.value) = n_Some_Required_Value
我用以下方式重写了它:
select value, func_value
from (select t.value, my_stored_function(t.value) func_value
from my_table t) subquery
where subquery.func_value = n_Some_Required_Value
让我们将 my_stored_function
视为资源消耗型查询。我假设,在第二个查询中,它被调用的次数减少了两次,但在此更改之后我没有遇到任何显着的性能提升。
所以,我想,我的假设是错误的。那么Oracle实际上是如何处理这些函数调用的呢?
guys. Say, I have a query:
select t.value, my_stored_function(t.value)
from my_table t
where my_stored_function(t.value) = n_Some_Required_Value
I have rewritten it in the following way:
select value, func_value
from (select t.value, my_stored_function(t.value) func_value
from my_table t) subquery
where subquery.func_value = n_Some_Required_Value
Let's think of my_stored_function
as of resource-consuming one. I assume, in the second query it is called twice less, but I didn't experience any significant performance increase after this change.
So, I guess, my assumption was wrong. How does Oracle actually process these function calls then?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
这是一个非常好的问题。
我首先尝试创建表并插入示例数据(仅五行):
我制作了一个简单的测试包来测试这一点。
现在
,我们可以在 Oracle 9i 上运行测试(在 11g 上结果相同):
结果是:
这是计划表:
这意味着为表的每一行(在 WHERE 计算中)调用该函数(在 WHERE 计算中)全表扫描的情况)。在 SELECT 语句中,启动的次数与条件 WHERE my_function = 1
现在...测试您的第二个查询(Oracle9i 和 11g 上的结果相同)
结果是:
简单地解释如下(对于选择优化器模式):
问题是:为什么 Count (SELECT) = 8?
因为 Oracle 首先运行子查询(在我使用全表扫描的情况下,它是 5 行 = 5 在 SELECT 语句中调用 my_function):
并且比这个视图(子查询就像视图)运行3次(由于subquery.func_value = 1的条件)再次调用函数my_function。
个人不建议在WHERE子句中使用函数,但我承认有时这是不可避免的。
最糟糕的示例如下所示:
Oracle 9i 上的结果是:
Oracle 11g 上的结果是:
在本例中,这表明有时使用功能可能对性能至关重要。在其他情况下(11g),它解决数据库本身的问题。
It's a really good question.
I first tried create table and insert sample data (five rows only):
I made a simple test package for testing this.
And body...
Now, we can run test on Oracle 9i (on 11g are same results):
Result is:
Here is plan table:
Which means that the function (in WHERE calues) is called for every row of the table (in the case of FULL TABLE SCAN). In the SELECT statement is launched just as many times comply with condition WHERE my_function = 1
Now... test your second query (same results on Oracle9i and 11g)
Result is:
Explain plain look like this (for CHOOSE optimizer mode):
QUESTION IS: Why Count (SELECT) = 8?
Because Oracle first run subquery (in my case with FULL TABLE SCAN, it's 5 rows = 5 calls my_function in SELECT statement):
And than for this view (subquery is like view) run 3 times (due to the condition where subquery.func_value = 1) again call function my_function.
Personally not recommend to use function in the WHERE clause, but I admit that sometimes this is unavoidable.
As the worst possible example of this is illustrated by the following:
Where the result on Oracle 9i is:
And on Oracle 11g is:
Which in this case shows that sometimes the use of functions may be critical for performance. In other cases (11g) it solves the database itself.
在这两种情况下,都会为my_table
中的每一行调用该函数一次。在第一种情况下,调用将作为where
子句的结果,并且刚刚找到的值将被返回,而无需再次计算。在第二种情况下,所有计算值将从子查询返回,然后由外部查询的where
子句进行过滤。编辑: 显然不是基于 true马丁的测试。现在我必须回去找到几年前让我认为情况确实如此的测试,看看我做错了什么。关于联邦调查局的那句话仍然是正确的。我希望。
内存使用情况可能存在一些细微的差异,优化器可能使用的确切计划也可能存在一些细微的差异,但我认为两者都不会很重要。几乎可以肯定不会反对函数调用本身的成本。
我认为优化这一点的唯一方法是使用基于函数的索引。
In both cases the function will be called once for every row inmy_table
. In the first case the call will be as a result of thewhere
clause and the value it's just found will be returned without being calculated again. In the second case all the calculated values will be returned from the subquery and will then be filtered by the outer query'swhere
clause.Edit: Apparently not true based on Martin's testing. Now I have to go back and find the testing I did years ago that made me think this was the case, and see what I did wrong. The bit about FBIs is still true. I hope.
There may be some minor difference in memory usage and possibly the exact plan used by the optimizer but I wouldn't have thought either would be significant. Almost certainly not against the cost of the function call itself.
The only way I can see to optimize this is with a function based index.
一个简单的测试:
结果(使用10g):
结论:该函数在SELECT和WHERE子句中分别执行。
A simple test:
Results (using 10g):
Conclusion: The function was executed separately in the SELECT and WHERE clauses.
您可以使用 PL/SQL 编译指示来影响 Oracle 优化查询的方式,请参阅 RESTRICT_REFERENCES 指令
You can use PL/SQL pragmas to affect the way oracle optimizes the query, see RESTRICT_REFERENCES Pragma