Home  >  Article  >  Database  >  在SQL中使用PL/SQL函数存在的问题

在SQL中使用PL/SQL函数存在的问题

WBOY
WBOYOriginal
2016-06-07 17:30:351080browse

很多不了解oracle数据库的开发人员很喜欢用PL/SQL的函数、存储等来达到代码上的简洁.

很多不了解Oracle数据库的开发人员很喜欢用PL/SQL的函数、存储等来达到代码上的简洁.

推荐阅读:

使用PL/SQL执行java存储来获得MAC地址  

如:

SELECT EMPNO,ENAME,DNAME,LOC FROM EMP,DEPT WHERE EMP.DEPTNO=DEPT.DEPTNO;

这样一个SQL,开发人员可能觉得冗长(这里假设SQL冗长),他们喜欢用函数,这样:

CREATE FUNCTION F_GETDEPTINFO(PDEPTNO NUMBER,PTYPE VARCHAR2)

RETURN VARCHAR2 AS

V_DEPTINFO VARCHAR2(50);

BEGIN

IF PTYPE='DNAME' THEN

SELECT DNAME INTO V_DEPTINFO FROM DEPT WHERE DEPTNO=PDEPTNO;

END IF;

IF PTYPE='LOC' THEN

SELECT LOC INTO V_DEPTINFO FROM DEPT WHERE DEPTNO=PDEPTNO;

END IF;

RETURN V_DEPTINFO;

END;

 

有的还会为函数加上异常处理,返回某些自定义的值.(我这里就没有加了)

最后,SQL就改写为:SELECT EMPNO,ENAME,F_GETDEPTINFO(DEPTNO,'DNAME'),F_GETDEPTINFO(DEPTNO,'LOC') FROM EMP;

这样开发人员认为SQL简洁多了,并且可能有的还认为性能会有提升.尤其是在处理某些复杂的业务逻辑的时候,SQL中PL/SQL函数使用的更为频繁.

由于对数据库的不熟悉,尤其不善于SQL的表连接等方式,大量的函数使用导致应用变的日益缓慢起来.所以在这里建议开发的TX们也多了解一下相应的数据库原理.

在这里我们来分析以下在SQL中使用PL/SQL函数存在的几个问题:

1.熟悉oracle数据库的人知道在oracle数据库中存在SQL引擎和PL/SQL引擎,分别用来处理sql语句和PLSQL语句.虽然在9i之后,SQL语句和PL/SQL语句可以共享同一个

解析器,但解析后的语句还是会在两个引擎之间进行切换,这势必会带来性能开销.

示例:

直接执行SQL语句

11:17:33 SCOTT@orcl> set autot trace
11:18:05 SCOTT@orcl> SELECT ROWNUM FROM dual CONNECT BY ROWNUM

1000000 rows selected.

Elapsed: 00:00:10.03

Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
          0  consistent gets
          0  physical reads
          0  redo size
  11846828  bytes sent via SQL*Net to client
    733734  bytes received via SQL*Net from client
      66668  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
    1000000  rows processed

可以看到性能基本在网络的I/O上.耗时10.03秒.

下面我们来在SQL中使用PL/SQL函数来完成同样的功能.

11:25:11 SCOTT@orcl> CREATE FUNCTION plsql_function(p_number IN NUMBER)
11:25:14  2  RETURN NUMBER AS
11:25:14  3  BEGIN
11:25:14  4    RETURN p_number;
11:25:14  5  END plsql_function;
11:25:15  6  /

Function created.

Elapsed: 00:00:00.04
11:25:28 SCOTT@orcl> SELECT plsql_function(ROWNUM) t FROM dual CONNECT BY ROWNUM

1000000 rows selected.

Elapsed: 00:00:13.50

Statistics
----------------------------------------------------------
        17  recursive calls
          0  db block gets
        24  consistent gets
          0  physical reads
          0  redo size
  11846823  bytes sent via SQL*Net to client
    733734  bytes received via SQL*Net from client
      66668  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
    1000000  rows processed

此时不仅有网络I/O,而且出现了缓存的I/O.耗时为13.50秒.

通过autotrace我们感觉到在SQL中使用PL/SQL函数会比直接使用SQL语句要慢。

注:这里AUTOTRACE信息不是很明显,可以通过之前介绍的DBMS_HPROF包来查看详细的性能信息.

这里我们再分析上面两个语句的SQL_TRACE情况.

直接使用SQL语句查询的SQL_TRACE如下:

PARSING IN CURSOR #11 len=48 dep=0 uid=84 oct=3 lid=84 tim=1359750169623584 hv=2961471920 ad='3a9180b0' sqlid='67j3zkks88ydh'
SELECT ROWNUM FROM dual CONNECT BY ROWNUM END OF STMT
PARSE #11:c=5999,e=5932,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=1,plh=1731520519,tim=1359750169623579
EXEC #11:c=0,e=218,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=1731520519,tim=1359750169624022
FETCH #11:c=1000,e=194,p=0,cr=0,cu=0,mis=0,r=1,dep=0,og=1,plh=1731520519,tim=1359750169624591
FETCH #11:c=0,e=136,p=0,cr=0,cu=0,mis=0,r=15,dep=0,og=1,plh=1731520519,tim=1359750169625626
...
FETCH #11:c=0,e=17,p=0,cr=0,cu=0,mis=0,r=15,dep=0,og=1,plh=1731520519,tim=1359750173026323

*** 2013-02-02 04:23:05.560
STAT #11 id=1 cnt=22441 pid=0 pos=1 obj=0 op='COUNT (cr=0 pr=0 pw=0 time=51932 us)'
STAT #11 id=2 cnt=22441 pid=1 pos=1 obj=0 op='CONNECT BY WITHOUT FILTERING (cr=0 pr=0 pw=0 time=30133 us)'
STAT #11 id=3 cnt=1 pid=2 pos=1 obj=0 op='FAST DUAL (cr=0 pr=0 pw=0 time=0 us cost=2 size=0 card=1)'
CLOSE #11:c=1000,e=511,dep=0,type=0,tim=1359750185560442

可以看到解析花费了一点时间,其后的EXE没有产生CPU TIME,也只有218的elapse time.

 

我们再来看看使用PL/SQL函数的SQL语句的trace:

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Previous article:MySQL主从热备份Next article:使用PL/SQL执行OS命令