1

我是 Oracle 的新手,我有两个将高频使用的功能。我想知道他们之间哪个更好。

这个:

FUNCTION GET_MY_MONEY (myType IN NUMBER) RETURN NUMBER AS
    var_amount   NUMBER;
    var_result   NUMBER;
BEGIN
    var_result := 0;
    var_amount := 0;
    SELECT amount INTO var_amount FROM mytable WHERE type = myType AND sysdate >= date_from AND sysdate <= date_to;
    var_result := var_amount*1000;
    RETURN var_result;
EXCEPTION
    WHEN OTHERS THEN
        RETURN 0;
END;

或者这个:

FUNCTION GET_MY_MONEY (myType IN NUMBER) RETURN NUMBER AS
    var_count    NUMBER;
    var_amount   NUMBER;
    var_result   NUMBER;
BEGIN
    var_result := 0;
    var_count := 0;
    var_amount := 0;
    SELECT count(*) INTO var_count FROM mytable WHERE type = myType AND sysdate >= date_from AND sysdate <= date_to;
    IF (var_count > 0) THEN
        SELECT amount INTO var_amount FROM mytable WHERE type = myType AND sysdate >= date_from AND sysdate <= date_to;
        var_result := var_amount*1000;
        RETURN var_result;
    ELSE RETURN 0; END IF;
EXCEPTION
    WHEN OTHERS THEN
        RETURN 0;
END;

哪个性能更好?当他们被调用时,哪个返回更快?

提前致谢。

4

3 回答 3

4

一般来说,这取决于。您将多久调用一次函数并传入一个myType导致查询返回 0 行的值?

如果在 99.9% 的调用中,查询将恰好返回 1 行,那么第二种方法将运行查询以执行两次。虽然第二次调用可能不会导致函数的成本是第一次调用的两倍,因为您感兴趣的块几乎可以保证被缓存,但第二种方法几乎肯定会慢得多。

另一方面,如果大部分调用将涉及myType不返回行的值,则第二种方法通常不必第二次执行查询。第一种方法会产生大部分时间处理异常的开销,这几乎肯定会比第二种查询更昂贵。

在大多数情况下,基于返回 0 行的概率,更有效的解决方案将是显而易见的。大多数时候,只有当调用者非常确信myType他们将传入的值是有效的时才会调用该函数,因此第一种方法最终会更有效。随着导致找到 0 行的调用比例增加,第二种方法变得更有效。该行的位置将取决于许多因素,尤其是您的表、数据、硬件和 Oracle 版本。您需要运行基准测试来确定您的特定代码的分界线是 10%、20% 还是 90%。

于 2013-04-26T06:04:18.577 回答
2

该问题已被编辑,但SELECT amount INTO var_amount ...如果有不止一行,则会失败。(也许你想选择sum(amount))。

第一种方法更好,因为:

  • 更容易理解
  • 你不扫描表两次。
  • 在第二个你得到 var_amount 但你不使用它。
  • count(*) 没用,你可以select nvl(sum(amount),0) as amount

date_from但是,您必须为日期变量(和)赋值date_to或将它们作为参数。你可以返回一个表达式,即:RETURN var_count*1000;

于 2013-04-26T05:53:01.137 回答
1

此外:

DECLARE
  v_retVal NUMBER:= 0;
  v_sal    NUMBER:= 0;
BEGIN
  SELECT nvl(sum(sal),0) as sal INTO v_sal 
    FROM scott.emp 
   WHERE deptno = 40; -- no data for deptno = 40 

   -- No exception needed, function will always return 0 or value --
   v_retVal:= (CASE WHEN v_sal = 0 THEN 0 ELSE v_sal*1000 END);

   dbms_output.put_line (v_retVal);

  -- RETURN v_retVal;
END;
/
于 2013-04-26T13:02:59.133 回答