Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 我应该在函数中使用异常而不是计数(*)?_Sql_Performance_Oracle - Fatal编程技术网

Sql 我应该在函数中使用异常而不是计数(*)?

Sql 我应该在函数中使用异常而不是计数(*)?,sql,performance,oracle,Sql,Performance,Oracle,我是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 WHER

我是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;
哪一种性能更好?哪一个在调用时返回更快


提前感谢。

问题已编辑,但请选择“金额到风险金额中…”。。。如果有多行,则将失败。可能要选择sumamount

第一种方法更好,因为:

更容易理解 您不需要扫描表两次。 第二 你得到了var_数量,但你没有使用它。 计数*是无用的,您可以选择nvlsumamount,0作为金额 但是,必须为日期变量sdate_from和date_指定一个值,或将其作为参数。
您可以返回一个表达式,即:returnvar_count*1000

问题已被编辑,但请选择“金额到风险金额中…”。。。如果有多行,则将失败。可能要选择sumamount

第一种方法更好,因为:

更容易理解 您不需要扫描表两次。 第二 你得到了var_数量,但你没有使用它。 计数*是无用的,您可以选择nvlsumamount,0作为金额 但是,必须为日期变量sdate_from和date_指定一个值,或将其作为参数。
您可以返回一个表达式,即:returnvar_count*1000

一般来说,这要视情况而定。调用函数并传入导致查询返回0行的myType值的频率如何

如果在99.9%的调用中,查询将只返回一行,那么第二种方法将运行要执行两次的查询。虽然第二次调用可能不会导致函数的开销是第一次调用的两倍,因为您感兴趣的块几乎可以保证被缓存,但第二种方法几乎肯定会大大降低速度

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


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

通常,这取决于您的代码。调用函数并传入导致查询返回0行的myType值的频率如何

如果在99.9%的调用中,查询将只返回一行,那么第二种方法将运行要执行两次的查询。虽然第二次调用可能不会导致函数的开销是第一次调用的两倍,因为您感兴趣的块几乎可以保证被缓存,但第二种方法几乎肯定会大大降低速度

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

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

此外:

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;
/
此外:

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

当记录数非常高时,第一种方法更好。因为计数*是一项繁重的任务,我会选择第一种方法。我认为你对使用的变量感到困惑。var_count没有在第一个中声明,第二个中也没有使用var_amount。@Gopeshharma你能解释一下计数*重是什么意思吗?你应该准确地找出你认为是什么错误
有效并专门捕获它们,而不是在其他情况下使用。您是否可以使用BETWEEN而不是=?当记录数非常高时,第一种方法更好。因为计数*是一项繁重的任务,我会选择第一种方法。我认为你对使用的变量感到困惑。var_count没有在第一个中声明,第二个中也没有使用var_amount。@Gopeshharma你能解释一下count*很重是什么意思吗?你应该准确地找出哪些错误是有效的,并专门捕获它们,而不是在其他错误出现时使用。你能不能用BETWEEN代替=?在我的情况下,可能超过80%的查询将返回0行。但在剩下的不到20%的情况下,这将花费2倍的时间来扫描足够大的表。你能解释为什么“处理异常的开销”更昂贵吗?我是新来的,我真的不知道Oracle处理异常时的幕后黑手是什么。对于分析来说,+1,尽管我认为异常开销等于零,而在函数的一小部分调用中,对sql引擎的第二次调用我不确定,这只是一个赌注。最好选择nvlsumamount,0。在我的例子中,可能超过80%的查询将返回0行。但在剩下的不到20%的情况下,这将花费2倍的时间来扫描足够大的表。你能解释为什么“处理异常的开销”更昂贵吗?我是新来的,我真的不知道Oracle处理异常时的幕后黑手是什么。对于分析来说,+1,尽管我认为异常开销等于零,而在函数的一小部分调用中,对sql引擎的第二次调用我不确定,这只是一个赌注。最好选择nvlsumamount,0.Yes,特别是在选择SUM时,在这种情况下您根本不需要捕获异常。是的,特别是在选择SUM时,在这种情况下您根本不需要捕获异常。