这是一个非常好的问题。
我首先尝试创建表并插入示例数据(仅五行):
create table my_table(value number);
insert into my_table(value) values(1);
insert into my_table(value) values(2);
insert into my_table(value) values(3);
insert into my_table(value) values(4);
insert into my_table(value) values(5);
我做了一个简单的测试包来测试这个。
create or replace package my_package is
g_counter_SELECT PLS_INTEGER := 0; -- counter for SELECT statement
g_counter_WHERE PLS_INTEGER := 0; -- counter for WHERE clause
function my_function(number_in in number, type_in in varchar2) return number;
procedure reset_counter;
end;
/
与身体...
create or replace package body my_package is
function my_function(number_in in number, type_in in varchar2) return number is
begin
IF(type_in = 'SELECT') THEN
g_counter_SELECT := g_counter_SELECT + 1;
ELSIF(type_in = 'WHERE') THEN
g_counter_WHERE := g_counter_WHERE + 1;
END IF;
return mod(number_in, 2);
end;
procedure reset_counter is
begin
g_counter_SELECT := 0;
g_counter_WHERE := 0;
end;
end;
/
现在,我们可以在 Oracle 9i 上运行测试(在 11g 上是相同的结果):
-- reset counter
exec my_package.reset_counter();
-- run query
select t.value, my_package.my_function(t.value, 'SELECT')
from my_table t
where my_package.my_function(t.value, 'WHERE') = 1;
-- print result
exec dbms_output.put_line('Count (SELECT) = ' || my_package.g_counter_SELECT);
exec dbms_output.put_line('Count (WHERE) = ' || my_package.g_counter_WHERE);
结果是:
DBMS Output (Session: [1] SCOTT@ORA9i at: 08.09.2010 01:50:04):
-----------------------------------------------------------------------
Count (SELECT) = 3
Count (WHERE) = 5
这是计划表:
--------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
--------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | |
|* 1 | TABLE ACCESS FULL | MY_TABLE | | | |
--------------------------------------------------------------------
这意味着该函数(在 WHERE 计算中)为表的每一行调用(在 FULL TABLE SCAN 的情况下)。在 SELECT 语句启动时,只要符合条件 WHERE my_function = 1
现在...测试您的第二个查询(Oracle9i 和 11g 上的结果相同)
结果是:
DBMS Output (Session: [1] SCOTT@ORA9i at: 08.09.2010 02:08:04):
-----------------------------------------------------------------------
Count (SELECT) = 8
Count (WHERE) = 0
解释如下(对于 CHOOSE 优化器模式):
--------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
--------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | |
|* 1 | TABLE ACCESS FULL | MY_TABLE | | | |
--------------------------------------------------------------------
问题是:为什么计数(SELECT)= 8?
因为 Oracle 首先运行子查询(在我的情况下使用 FULL TABLE SCAN,它是 5 行 = 5 在 SELECT 语句中调用 my_function):
select t.value, my_package.my_function(t.value, 'SELECT') func_value from my_table t
而对于这个视图(子查询就像视图)运行 3 次(由于 subquery.func_value = 1 的条件)再次调用函数 my_function。
个人不建议在 WHERE 子句中使用函数,但我承认有时这是不可避免的。
最糟糕的例子如下所示:
select t.value, my_package.my_function(t.value, 'SELECT')
from my_table t
where my_package.my_function(t.value, 'WHERE') = my_package.my_function(t.value, 'WHERE')
and my_package.my_function(t.value, 'WHERE') = my_package.my_function(t.value, 'WHERE')
and my_package.my_function(t.value, 'WHERE') = my_package.my_function(t.value, 'WHERE')
and my_package.my_function(t.value, 'WHERE') = my_package.my_function(t.value, 'WHERE')
and my_package.my_function(t.value, 'WHERE') = my_package.my_function(t.value, 'WHERE');
Oracle 9i 上的结果是:
Count (SELECT) = 5
Count (WHERE) = 50
在 Oracle 11g 上是:
Count (SELECT) = 5
Count (WHERE) = 5
在这种情况下,这表明有时函数的使用可能对性能至关重要。在其他情况下(11g)它解决了数据库本身。