对于Oracle,对于数据修改的操作通过存储过程处理,而对于函数一般不进行数据修改操作。同时,函数可以通过 Select 进行调用,而存储过程则不行。

一、对于volatile 函数的行为

1、Oracle 行为

创建函数:

  1. create or replace function fun01 return number as
  2. begin
  3. insert into t1 values(1);
  4. return 1;
  5. end;
  6.  
  7. create or replace function fun02 return number as
  8. v_cnt number;
  9. begin
  10. select count(*) into v_cnt from t1;
  11. return v_cnt;
  12. end;

(1)、函数有修改操作,不允许select 调用

有修改操作,不允许 select 调用:

  1. SQL> select fun01() from dual;
  2. select fun01() from dual
  3. *
  4. ERROR at line 1:
  5. ORA-14551: cannot perform a DML operation inside a query
  6. ORA-06512: at "SYS.FUN01", line 3

没有修改操作,可以select 调用:

  1. SQL> select fun02() from dual;
  2.  
  3. FUN02()
  4. ----------
  5. 2

有修改操作的函数,只能通过call 调用

  1. SQL> var a number;
  2. SQL> call fun01() into :a;
  3.  
  4. Call completed.

(2)、视图包含函数的情景

  1. create or replace view v_t2 as select id, fun01() as t1_cnt from t2;
  2.  
  3. test=# select count(*) from v_t2;
  4. count
  5. -------
  6. 2
  7. (1 row)

经验证,虽然 fun01 含有 insert 操作,但实际函数(fun01)是没有调用的,也就是函数内的 insert 没有执行。这个个人理解应该是个不严谨的地方。

2、PostgreSQL 行为

创建函数:

  1. create or replace function fun01() returns number as
  2. $$
  3. begin
  4. insert into t1 values(1);
  5. return 1;
  6. end;
  7. $$
  8. language plpgsql;

(1)、函数有修改操作,可以通过Select 调用

  1. test=# select count(*) from t1;
  2. count
  3. -------
  4. 3
  5. (1 row)
  6.  
  7. test=# select fun01();
  8. fun01
  9. -------
  10. 1
  11. (1 row)
  12.  
  13. test=# select count(*) from t1;
  14. count
  15. -------
  16. 4
  17. (1 row)

(3)、视图包含函数的情景

  1. create or replace view v_t2 as select id, fun01() as t1_cnt from t2;
  2.  
  3. test=# select count(*) from v_t2;
  4. count
  5. -------
  6. 2
  7. (1 row)

经验证,查询视图时,针对每一行,都会调用fun01 函数一次,也就是 insert 操作实际发生的。

二、对于Stable函数的行为

以上的例子中,由于函数含有insert 操作,因此,函数只能是 volatile。 如果函数是 stable or immutable,那又是何种现象了?

构建数据: t1 表的数据量比较大,count(*) 一次大概要2秒

  1. test=# create table t1(id integer,name text);
  2. CREATE TABLE
  3. test=# create table t2(id integer);
  4. CREATE TABLE
  5.  
  6. insert into t1 select generate_series(1,50000000),'a';
  7. insert into t2 select generate_series(1,10);
  8.  
  9. test=# select count(*) from t1;
  10. count
  11. ----------
  12. 50000000
  13. (1 row)
  14.  
  15. Time: 2059.901 ms (00:02.060)

  

创建函数与视图

  1. create or replace function test_volatile(id integer)
  2. returns bigint
  3. volatile
  4. language sql
  5. as
  6. $$ select count(*) from t1 $$ ;
  7. /
  8.  
  9. create or replace function test_stable(id integer)
  10. returns bigint
  11. stable
  12. language sql
  13. as
  14. $$ select count(*) from t1 $$ ;
  15. /
  16.  
  17. create or replace function test_immutable(id integer)
  18. returns bigint
  19. immutable
  20. language sql
  21. as
  22. $$ select count(*) from t1 $$ ;
  23. /
  24.  
  25. create view v_t2_volatile as select id,test_volatile(1) from t2;
  26. create view v_t2_stable as select id,test_stable(1) from t2;
  27. create view v_t2_immutable as select id,test_immutable(1) from t2;

  

验证视图的访问效率:immutable or stable 类型的函数实际一次都没有执行。

  1. test=# select count(*) from v_t2_immutable;
  2. count
  3. -------
  4. 10
  5. (1 row)
  6.  
  7. Time: 1.027 ms
  8.  
  9. test=# select count(*) from v_t2_stable;
  10. count
  11. -------
  12. 10
  13. (1 row)
  14.  
  15. Time: 0.950 ms
  16. test=# select count(*) from v_t2_volatile;
  17. count
  18. -------
  19. 10
  20. (1 row)
  21.  
  22. Time: 23231.599 ms (00:23.232)

  

三、性能“问题”

对于 select count(*) from v_t2 (视图),由于 oracle 并不执行函数 ,因此,性能肯定更快。而对于 postgresql,针对每条都要调用一次函数,性能上肯定更慢。

Oracle 与 PostgreSQL 函数行为的差异引发性能差异的更多相关文章

  1. MySQL&SQL server&Oracle&Access&PostgreSQL数据库sql注入详解

    判断数据库的类型 当我们通过一些测试,发现存在SQL注入之后,首先要做的就是判断数据库的类型. 常用的数据库有MySQL.Access.SQLServer.Oracle.PostgreSQL.虽然绝大 ...

  2. oracle VS postgresql系列-行列转换

    [需求]例如先有数据为 id | name ------+--------- | lottu | xuan | rax | ak | vincent 现在需要转换为 id | names ------ ...

  3. postgresql 函数 参数为复合类型

    postgresql没有存储过程,但是函数功能很强大. 在近期开发的电商管理平台中,对于产品的类目管理,设计时有个属性字段,设为字符数组,但是EF不支持数组的操作,所以在添加和修改类目时,需要对属性的 ...

  4. ORACLE当中自定义函数性优化浅析

    为什么函数影响性能 在SQL语句中,如果不合理的使用函数(Function)就会严重影响性能,其实这里想说的是PL/SQL中的自定义函数,反而对于一些内置函数而言,影响性能的可能性较小.那么为什么SQ ...

  5. [转载]ORACLE日期时间函数大全

    ORACLE日期时间函数大全 TO_DATE格式(以时间:2007-11-02   13:45:25为例)           Year:              yy two digits 两位年 ...

  6. Oracle的pipelined函数实现高性能大数据处理

    从Oracle 8开始,我们就可以从一个collection类型的数据集合中查询出数据,这个集合称之为"虚拟表".它的方法是"SELECT FROM TABLE(CAST ...

  7. 【转帖】从 Oracle 到 PostgreSQL ,某保险公司迁移实践 技术实践

    从 Oracle 到 PostgreSQL ,某保险公司迁移实践 http://www.itpub.net/2019/11/08/4108/ 信泰人寿保险股份有限公司 摘要:去O一直是金融保险行业永恒 ...

  8. Oracle 与 postgreSQL 事务处理区别(多版本与undo区别)

    2015年左右,因为工作需要用MongoDB.CouchBase这两种文档型数据库,时不时到这两个数据库官网上查资料.报BUG.时常可以在MongoDB官网上看到这样一些新闻,“某某企业成功将MySQ ...

  9. Sql获取表所有列名字段——select * 替换写法,Sqlserver、Oracle、PostgreSQL、Mysql

    实际开发中经常用到select * from table,往往需要知道具体的字段,这个时候再去数据库中翻或者查看数据字典比较麻烦.为了方便,自己特意写了一个小函数f_selectall,针对SqlSe ...

随机推荐

  1. python基础知识-day8(函数实战)

    1 def out(): 2 username=input("请输入用户名:\n") 3 password=input("请输入密码:\n") 4 return ...

  2. SAP APO-主数据设置

    可以在SAP APO的相关组件中创建主数据,也可以将其从SAP R / 3传输到SAP APO. 可以使用核心接口(CIF)将其传输到SAP APO模块. 在主数据集成模型中,您定义将主数据传输到SA ...

  3. SpringBoot之缓存

    一.准备工作 首先整合使用Spring整合MyBatis. 可参阅:SpringBoot整合MyBatis SpringBoot整合MyBatis完后后,我们需要在pom.xml中添加缓存相关的依赖. ...

  4. ServletContext 对象

    概念:代表整个Web应用 可以和程序的容器通信 (服务器) 获取 通过request对象获取  request.getServletContext(); 通过HTTPServlet获取  this.g ...

  5. Java封装Get/Post类

    封装的类: package pers.hmi.translate; import java.io.BufferedReader; import java.io.IOException; import ...

  6. js导入excel&导出excel

    Excel导入 html代码 <button style={{ color: '#1890ff', fontSize: '14px', cursor: 'pointer' }} onClick= ...

  7. APISpace 分钟级降水预报API接口 免费好用

    各种不同类型的降水对国民经济和国防建设会产生不同的影响.无论农业生产.航空.航海.交通运输.水利建设.防涝防旱等都需要以及准确的降水预报.   分钟级降水预报API,支持国内任一经纬度的预报数据,实时 ...

  8. 好串_via牛客网

    题目 链接:https://ac.nowcoder.com/acm/contest/28537/C 来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K,其他语言 ...

  9. Codeforces Round #792 (Div. 1 + Div. 2) // C ~ E

    比赛链接:Dashboard - Codeforces Round #792 (Div. 1 + Div. 2) - Codeforces C. Column Swapping 题意: 给定一个n*m ...

  10. CF1700C Helping the Nature

    题目大意: 给出一个长度为 n 的序列 a,每次可以进行三种操作中的一种: 选择i,将 a_1,a_2,...,a_i减1. 选择i,将 a_i,a_i+1,...,a_n减1. 将所有 a_i加1. ...