1

我在 Oracle 中编写了一些存储函数。其中一个是一个非常基本的函数,它以字符串作为参数并返回另一个字符串。这是我的功能:

CREATE OR REPLACE 
FUNCTION get_mail_custcode (
    custcodeParam IN customer_table.custcode%TYPE)
    RETURN VARCHAR2
IS
    mail_rc   contact_table.email%TYPE;
BEGIN
    SELECT   cc.email
      INTO   mail_rc
      FROM   contact_table cc, customer_table cu
     WHERE       cu.customer_id = cc.customer_id
             AND cu.custcode like custcodeParam ;

    RETURN mail_rc ;
END;

所以它不起作用..该功能似乎运行良好但没有任何结束执行..该功能是工作时间和时间,我在2或3分钟后手动取消操作(此查询通常会立即产生结果)。在一次又一次地编写查询之后,我终于(并且随机)将其更改cu.custcode like custcodeParam为 acu.custcode = custcodeParam并且它正在工作!

所以我的问题是为什么?为什么我不能like在存储函数中使用比较器?为什么这不会出错,但函数会无限期地运行。

谢谢。

4

1 回答 1

3

游标在 Oracle 中的处理方式都是一样的。函数中的查询将被视为与您通过 SQL*Plus 手动输入的查询完全相同。

但是,您的示例中可能不同的是 Oracle 如何处理变量。以下两个查询与优化器根本不同:

SELECT * FROM tab WHERE code LIKE 'FOO%';

variable v_code VARCHAR2(4)
EXEC :v_code := 'FOO%';
SELECT * FROM tab WHERE code LIKE :v_code;

在第一种情况下,优化器查看常量FOO%并立即判断索引code非常适合通过索引 RANGE SCAN 快速检索行。

在第二种情况下,优化器必须考虑它:V_CODE不是恒定的。优化器的目的是确定一个查询的计划,该计划将由同一查询的连续执行共享(因为计算计划是昂贵的)。

优化器的行为取决于您的 Oracle 版本:

  • 在旧的 Oracle 版本(9i 和更早版本)中,变量的值被忽略以构建计划。实际上,无论传递给它的价值如何,甲骨文都必须制定一个有效的计划。在您的情况下,这可能会导致完全扫描,因为 Oracle 必须采取风险最小的选项并认为这FOO%很可能是一个值%FOO(后者不能通过索引范围扫描有效访问)。
  • 在 10g Oracle 中引入了绑定窥视:现在优化器可以访问变量的值并生成合适的计划。主要问题是,在大多数情况下,一个查询只能有一个计划,这意味着曾经传递给函数的第一个变量的值将强制执行所有后续执行的执行计划。如果要传递的第一个值是%FOO,则可能会选择 FULL SCAN。
  • 在 11g 中,Oracle 具有“智能游标共享”:单个查询可以共享多个计划,在上面的示例中,该值FOO%将使用 RANGE SCAN,而%FOO可能会使用 FULL SCAN。

您使用的是什么版本的 Oracle?


更新

在 10g 和之前的版本中,如果这个函数经常在没有通配符的情况下使用,你应该重写它以确认优化器的行为:

BEGIN
   IF instr(custcodeParam, '%') > 0 OR instr(custcodeParam, '_') > 0 THEN
      SELECT cc.email
        INTO mail_rc
        FROM contact_table cc, customer_table cu
       WHERE cu.customer_id = cc.customer_id
         AND cu.custcode LIKE custcodeParam;
   ELSE
      SELECT cc.email
        INTO mail_rc
        FROM contact_table cc, customer_table cu
       WHERE cu.customer_id = cc.customer_id
         AND cu.custcode = custcodeParam;
   END IF;

   RETURN mail_rc;
END;
于 2013-04-25T08:38:15.943 回答