function在查询语句里的运行次数

首先建一package,我们后面要调用这个package,计数用

CREATE OR REPLACE PACKAGE PKG_TEST IS
  ID NUMBER;
  FUNCTION GET_ID RETURN NUMBER;
  PROCEDURE SETID(V_ID NUMBER);
END PKG_TEST;
/
CREATE OR REPLACE PACKAGE BODY PKG_TEST IS
  FUNCTION GET_ID RETURN NUMBER IS
  BEGIN
    ID := ID + 1;
    RETURN ID;
  END;
  PROCEDURE SETID(V_ID NUMBER) IS
  BEGIN
    ID := V_ID;
  END;  
END;
/


首先直接查询

SQL> exec pkg_test.SETID(0);
PL/SQL procedure successfully completed

SQL> select pkg_test.get_id from dual group by pkg_test.get_id;
    GET_ID
----------
         1
此时函数执行了一次。


SQL> exec pkg_test.SETID(0);
PL/SQL procedure successfully completed

SQL> select pkg_test.get_id from dual where pkg_test.get_id >=1 group by pkg_test.get_id;
    GET_ID
----------
         2
此时函数执行了两次。

大家都知道用函数会很慢,有没有办法让它运行一次呢?

当然可以。

SQL> exec pkg_test.SETID(0);
PL/SQL procedure successfully completed

SQL> select id from (select rownum as sn,pkg_test.get_id as id from dual) where id >=0 group by id;
        ID
----------
         1


如果是select里,即使引用了多次,也只会执行一次

SQL> exec pkg_test.SETID(0);
PL/SQL procedure successfully completed
SQL> select pkg_test.get_id from dual group by pkg_test.get_id;
    GET_ID
----------
         1

SQL> select pkg_test.get_id,pkg_test.get_id+1 as c2,pkg_test.get_id+2 as c3 from dual group by pkg_test.get_id;
    GET_ID         C2         C3
---------- ---------- ----------
         2          3          4

SQL> /
    GET_ID         C2         C3
---------- ---------- ----------
         3          4          5

SQL> 


部分情况下可以用DETERMINISTIC优化

SQL> exec pkg_test.SETID(0);
PL/SQL procedure successfully completed

SQL> select pkg_test.get_id from dual connect by level <=5;
    GET_ID
----------
         1
         2
         3
         4
         5
5 rows selected


加 DETERMINISTIC 后

CREATE OR REPLACE PACKAGE pkg_test IS
  id NUMBER;
  FUNCTION get_id RETURN NUMBER DETERMINISTIC;
  PROCEDURE setid(v_id NUMBER);
END pkg_test;
/
CREATE OR REPLACE PACKAGE BODY pkg_test IS
  FUNCTION get_id RETURN NUMBER DETERMINISTIC AS  
  BEGIN
    id := id + 1;
    RETURN id;
  END;
  PROCEDURE setid(v_id NUMBER) IS
  BEGIN
    id := v_id;
  END;
END;
/

SQL> select pkg_test.get_id from dual connect by level <=5;
    GET_ID
----------
         1
         1
         1
         1
         1
5 rows selected

另外,函数有个小问题:当不使用group by 时一行多次引用,会执行多次
SQL> SELECT pkg_test.get_id AS a, pkg_test.get_id AS b, pkg_test.get_id AS c from dual;
         A          B          C
---------- ---------- ----------
         1          2          3
1 row selected

即使当作表达式的一部分也不行

SQL> SELECT pkg_test.get_id + 0 AS a, pkg_test.get_id + 0 AS b, pkg_test.get_id + 0 AS c from dual;
         A          B          C
---------- ---------- ----------
         4          5          6
1 row selected

对于这种问题同样可以采用前面的方法,嵌套一次查询,只是需要多用一个小技巧(rownum >=1)

SQL> exec pkg_test.SETID(0);
PL/SQL procedure successfully completed

SQL> SELECT id AS a, id AS b, id AS c from (SELECT pkg_test.get_id as id from dual where rownum >=1);
         A          B          C
---------- ---------- ----------
         1          1          1
1 row selected


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值