当前位置: 首页 > 面试题库 >

Oracle如何处理SQL中的存储函数调用?

董高逸
2023-03-14
问题内容

伙计们。说,我有一个查询:

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实际如何处理这些函数调用?


问题答案:

这是一个非常好的问题。

我首先尝试创建表并插入示例数据(仅五行):

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    |       |       |       |
--------------------------------------------------------------------

问题是: 为什么计数(选择)= 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),它可以解决数据库本身。



 类似资料:
  • 我有如下db模式: 我用java调用以下代码: 代码生成异常: org.postgresql.util。PSQLException:错误:无法确定多态类型,因为输入的类型为“未知” 生成的查询是: 插入“public”。“some\u table”(“some\u col”)值(“public”。“some\u fun”(“{”1“}”)) 结果表明,jooq没有显式地对数组进行类型转换,post

  • 问题内容: SQL Server2005支持CLR,所以这意味着我们可以在后端使用CLR,所以该怎么做。我在c#中有一些函数,它对日期时间变量进行了一些复杂的操作,现在我想在SP中使用这些函数。首先,可以这样做。 问题答案: 是的,可以在SQL Server 2005数据库中使用.NET。请注意,SQL Server 2005支持的.NET版本是2.0。 这是使用Visual Studio制作CL

  • 问题内容: 如何在具有varchar数据类型且单引号的列中插入记录? 示例 :名字是,姓氏是 问题答案: 使用两个单引号 或者,使用新的(10g +)报价方法 :

  • 问题内容: 我想比较两列中的两个日期并得到最大值,然后再与日期值进行比较。这两列也可以容纳NULL值,例如我想要下面的OUTPUT。如何使用最大的函数或是否有任何东西else。我再次使用输出与另一个日期进行比较。 问题答案: 在您的选择中使用Oracle结构:

  • 我正在尝试在Spring Data Repository的nativeQuery中使用oracle的NVL函数。 当我在参数中传递值时,它会抛出异常如果我在“programId”中传递有效值,那么它工作正常。 例外情况:

  • 本文向大家介绍oracle中存储函数与存储过程的区别介绍,包括了oracle中存储函数与存储过程的区别介绍的使用技巧和注意事项,需要的朋友参考一下 在oracle中,函数和存储过程是经常使用到的,他们的语法中有很多相似的地方,可是也有它们的不同之处,这段时间刚学完函数与存储过程,来给自己做一个总结: 一:存储过程:简单来说就是有名字的pl/sql块。 语法结构:      案例: