开发者社区> 长烟慢慢> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

PL/SQL专家指南2——PL/SQL精髓

简介: 1、入门级概述 用PL/SQL很久了,很多其他搞IT的人问我PL/SQL是什么,一般我的回答是:1,Oracle的开发语言。2,比SQL复杂了些,多了很多东西(至于什么东西,现在还搞不清楚,还幼稚的以为:PL/SQL=PLus SQL),今天仔细潜心读了...
+关注继续查看

1、入门级概述

用PL/SQL很久了,很多其他搞IT的人问我PL/SQL是什么,一般我的回答是:1,Oracle的开发语言。2,比SQL复杂了些,多了很多东西(至于什么东西,现在还搞不清楚,还幼稚的以为:PL/SQL=PLus SQL),今天仔细潜心读了些书终于完善了这个定义(不是偷懒复制的,是手抄的):

Procedure Language/SQL(PL/SQL) is Oracle Corporation's procedure language extension to SQL, the standard data access language for relational databases.PL/SQL offers software engineering features such as data encapsulation, exception handling, information hiding, objects orientation, and brings state-of-the-art programming to the Oracle Sever and toolset.


当应用程序(如sql*plus)与数据库服务器进行连接的时候,用户进程(user process)使用SQL*NET发送连接请求。服务器上的listener接收这个请求,然后创建一个专用的服务器进程(dedicated server process)对请求进行处理。

用户全局区在使用专用服务器时,UGA位于PGA中,而在运行MTS(共享服务器)时,UGA位于SGA中。可以利用如下脚本查看当前UGA的大小:

SELECT   SUBSTR (a.NAME, 9, 10) "Name",
            ROUND (SUM (b.VALUE) / 1024 / 1024,
                   1)
         || ' M' "Total UGA for all sessions"
    FROM v$statname a, v$sesstat b
   WHERE a.statistic# = b.statistic# AND a.NAME = 'session uga memory'
GROUP BY a.NAME;

Name                 Total UGA for all sessions
-------------------- ------------------------------------------
uga memory                 8.7 M

注意,这里显示的是对所有活跃会话的统计,如果数据库配置为专用服务器,那么每个进程只能获得自己的PGA,因此也只能获得自己的UGA大小。所以,要确定分配给UGA的所有内存空间,唯一的方法就是要确定进程总数。

2、PL/SQL体系结构

oracle中有一个处理PL/SQL程序单元的编译器,该编译器首先创建语法树,然后利用优化器转化成机器代码存放在数据库中,以便稍后执行。9i加入了本地编译,把代码转换为数据库主机上的C语言共享库。因为oracle在处理计算密集型的PL/SQL程序时不需要对指令作过多的解释,所以这类程序的执行效率得到了提高。

PL/SQL虚拟机SQL引擎的辅助下,执行码在PL/SQL引擎上运行。当调用某一程序单元时,经过解释编译的代码将相应的机器代码(MCode)堆栈加载到SGA中,PL/SQL虚拟机负责处理这些指令,与RDBMS内核进行通信。在SQL引擎的辅助下,PL/SQL引擎执行指令配合SQL语句工作。

如果程序单元使用本地编译,而不是将机器代码堆栈加载到SGA中进行编译,共享库就加载到PGA中,尽管不需要对代码做任何解释,但是这种情况下仍需要PL/SQL虚拟机,同时,PL/SQL和SQL引擎也和做解释时一样行使相同的功能。

下面解释一下SQL引擎和PL/SQL 引擎是什么?

你可以认为SQL就是DDL或DML语句,而PL/SQL就是function procedure trigger package等程序段,包括匿名块等。
业务逻辑比较复杂时,单靠SQL就解决不了,需要配合一些程序代码来实现,比如java或C+SQL。java或C代码在client上执行,而SQL要在server上执行,client、servr之间需要进行较多的交互,效率较低。
为了提高效率,就有了PL/SQL。client向server发起一个PL/SQL请求,server的PL/SQL引擎就开始执行,在需要时会调用SQL引擎执行
SQL语句。PL/SQL引擎执行完毕后,向client发回结果。plsql中的sql代码还是交给sql引擎的,只有plsql代码交给plsql引擎,然后两个引擎之间相互联系,把结果传到client端


前期绑定和后期绑定:

前期绑定是指在代码执行前编译,进行命名空间验证、权限和语法检查。由于在编译时已经完成了大部分工作,这为执行节省了相当多的时间。oracle PL/SQL就是采用的前期绑定

后期绑定是指代码在执行时编译,由于在编译时和执行时都能进行修改,因此使用后期绑定的语言非常灵活。


3、PL/SQL编译步骤

编译器前端:

步骤1:语法分析——语法分析的主要功能是生成Diana(descriptive intermediate attribute notation for ada:ada的中间属性描述符号(ada是一种编程语言))。Dinan是描述程序的AST(abstract syntax tree:抽象语法树),只要对程序进行编译,就会创建一个Dinan实例并保存在数据库中。编译器在最后完成运行时,(编译相关对象,分析类型和包的规范说明等任务时)都要用到这个Diana实例。

从名称上看,Diana使用的是Ada编程语言,像Ada一样,oracle PL/SQL使用一种称为IDL(interface descriptive language:接口描述语言)的元符号定义Diana。oracle中的IDL(接口描述语言)称为FIDL(fuction IDL,IDL函数)。。。读到这里我们可以归纳一下,Diana是由一种接口描述语言来定义的,这种接口描述语言叫FIDL。

Diana是一种树形结构抽象类型,提供关于plsql代码的元数据。虽然PL/SQL编译器是使用C语言编写的,但是Diana有几个 为库和其他数据结构  提供信息的 内置PL/SQL程序包。一个与Diana相关的程序包是DIANA(重名) 。 另一个实用程序包是DIUIL。DIUIL程序包创建脚本diutil.sql。在$ORACLE_HOME/rdbms/admin中(我找到了)。

对于与Diana相关的PL/SQL对象的大小存在一些限制。这些限制不是取决于代码行的数量,而是取决于代码生成Diana的节点数量。如何检测代码的大小呢?一种方法是查看user_object_size视图。这个视图根据如下几个表返回代码大小:

IDL_CHAR$

IDL_SB4$

IDL_UB1$

IDL_UB2$

上面这些表在数据库中保存已编译的代码。要在user_object_size中检测代码的大小,用下面的程序包示例(也可以在即查询),我们之所以用这个包,正好可以来查询这个包在解析中Diana的大小:

CREATE OR REPLACE PACKAGE diana_size
AS
   PROCEDURE get_parsed_size(
      i_object_name IN VARCHAR2, 
      cv_result IN OUT SYS_REFCURSOR);
END diana_size;
/


CREATE OR REPLACE PACKAGE BODY diana_size
AS
   PROCEDURE get_parsed_size(
      i_object_name IN VARCHAR2,
      cv_result IN OUT SYS_REFCURSOR)
   IS
   BEGIN
      OPEN cv_result FOR
      SELECT name, type, parsed_size
      FROM user_object_size
      WHERE name = i_object_name;
  
   END get_parsed_size;
END;
/

SQL> variable x refcursor
SQL> exec diana_size.get_parsed_size('DIANA_SIZE',:x)
PL/SQL 过程已成功完成。
SQL> print x
NAME                            TYPE                          PARSED_SIZE
------------------------------ -------------                  -----------
DIANA_SIZE                     PACKAGE                  320
DIANA_SIZE                     PACKAGE BODY        0

程序包的规范中有一个PARSED_SIZE变量值,但是在程序包的实体中却不存在。这是什么原因呢? 原来在数据库服务器编译成功后,会丢弃

根据程序包和对象类型体所生成的Diana。因此他们的大小当然为0.

oracle提供一个很少人知道,并使用过的脚本对Diana进行检查。可以从$ORACLE_HOME/RDBMS/admin/dumpdian.sql中找到脚本(我找到了)

在语法分析中,除了创建Diana实例,还要与RDBMS SQL语法分析器通信来探测和引用绑定AST(抽象语法树,也就是Diana所描述的东东)。SQL语法分析器对PL/SQL和SQL*plus 的通用性保证率SQL语法在SQL*plus 和 PL/SQL中都是有效的。

在进行语法分析期间要执行的一个更为重要的任务,就是必须用到WRAP使用程序的功能,WRAP隐藏了源代码(实际上没有加密)。包装后的代码无法由人工解读,但是对oracle却不存在这个问题。为了WRAP代码,Diana以一个字节数组的形式写入平面文件。


步骤2:语义分析——语义分析将在语法分析步骤中生成的AST作为输入。下面是在语义分析中所要执行的几个任务:

***完成名称解析(包括函数重载)

***构造类型继承的层次结构

***确定代码的依赖关系

***与RDBMS SQL语法分析器一起,共同对SQL语句进行语义检查。

由于语义分析步骤并不实际生成代码,所以这里最重要的功能就是准备好Diana实例,在下一步中提交代码生成器处理。在完成语义分析后,带有注释的AST将被送往代码生成器。


编译器后端:

编译器前端对代码树的分析和映射做了大量处理,PL/SQL编译器后端将尝试生成和优化用于描述PL/SQL对象的机器代码。其实,将Diana实例转化为机器代码。要大致经过如下步骤:PL/SQL代码经过语法分析 ——生成Diana实例——经过语义分析——生成代码——由Diana创建IL——局部和全局优化——将IL转化为MCode

步骤3:代码生成——代码生成器输入的是Diana,输出的是MCode。

更细一步,代码生成器在第一阶段使用ILGEN(IL Generator:中间语言生成器)将PL/SQL程序的Diana实例转换为IL(intermediate language:中间语言)形式。Diana实例在转换成IL之前会保存在数据库中。

第二阶段,引入了局部和全局优化器。局部优化器对IL进行扫描,去掉其中许多低效内容,所有PL/SQL对象都要经过局部优化器的快速处理,这对提高最终机器代码的执行效率是不可或缺的。全局优化器的执行速度就没有那么高了,它在局部优化器处理之后启动,对PL/SQL对象进行控制流程分析、异常处理、去除无效和冗余代码的处理。这两个优化器的目的都是为了提高最终机器代码的运行时性能。

第三个阶段,也是最后一个阶段,将IL转换为MCode。MCode存放在数据库中,他就是执行PL/SQL程序单元时的执行码,使用PL/SQL虚拟机合一解释执行MCode。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
SQL点滴9—SQL Server中的事务处理以及SSIS中的内建事务
我们可以把SSIS中的整个package包含在一个事务中,但是如果在package的执行过程中有一个表需要锁定应该怎么处理呢?SSIS内建的事务处理可以解决这个问题。在此之前首先来熟悉一下SQL Server中的事务的概念。
661 0
SQL SERVER 取所有表及注释 和 字段属性
取表信息   select   sysobjects.name,sys.extended_properties.value   from   sysobjects left join sys.
712 0
【2011-04-06】SQL Server 2000 日志传送搭建
基本参考:   http://www.99inf.net/DB/SqlServer/223.htm 里面的内容很全。 有以下几点需要提前做的。   用来放置主服务器的日志备份的文件夹我们就叫 logfile    错误:无法访问 logfile   原因:没有设置共享的权限  解决办法:logfile 里面只是设置了安全里面的权限是不够的,要需要设置共享里面的权限   错误:错误代码 14261 指定的 primary_server_name.primary_database_name('S')已经存在。
801 0
+关注
长烟慢慢
系统架构师
文章
问答
文章排行榜
最热
最新
相关电子书
更多
SQL Sever迁移PG经验
立即下载
用SQL做数据分析
立即下载
SQL Server在电子商务中的应用与实践
立即下载