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。

相关文章
|
4天前
|
SQL 存储 Oracle
Oracle的PL/SQL定义变量和常量:数据的稳定与灵动
【4月更文挑战第19天】在Oracle PL/SQL中,变量和常量扮演着数据存储的关键角色。变量是可变的“魔术盒”,用于存储程序运行时的动态数据,通过`DECLARE`定义,可在循环和条件判断中体现其灵活性。常量则是不可变的“固定牌”,一旦设定值便保持不变,用`CONSTANT`声明,提供程序稳定性和易维护性。通过 `%TYPE`、`NOT NULL`等特性,可以更高效地管理和控制变量与常量,提升代码质量。善用两者,能优化PL/SQL程序的结构和性能。
|
29天前
|
SQL Perl
PL/SQL经典练习
PL/SQL经典练习
13 0
|
29天前
|
SQL Perl
PL/SQL编程基本概念
PL/SQL编程基本概念
13 0
|
1月前
|
SQL Perl
PL/SQL Developer 注册机+汉化包+用户指南
PL/SQL Developer 注册机+汉化包+用户指南
16 0
|
4天前
|
SQL Oracle 关系型数据库
Oracle的PL/SQL游标属性:数据的“导航仪”与“仪表盘”
【4月更文挑战第19天】Oracle PL/SQL游标属性如同车辆的导航仪和仪表盘,提供丰富信息和控制。 `%FOUND`和`%NOTFOUND`指示数据读取状态,`%ROWCOUNT`记录处理行数,`%ISOPEN`显示游标状态。还有`%BULK_ROWCOUNT`和`%BULK_EXCEPTIONS`增强处理灵活性。通过实例展示了如何在数据处理中利用这些属性监控和控制流程,提高效率和准确性。掌握游标属性是提升数据处理能力的关键。
|
4天前
|
SQL Oracle 安全
Oracle的PL/SQL循环语句:数据的“旋转木马”与“无限之旅”
【4月更文挑战第19天】Oracle PL/SQL中的循环语句(LOOP、EXIT WHEN、FOR、WHILE)是处理数据的关键工具,用于批量操作、报表生成和复杂业务逻辑。LOOP提供无限循环,可通过EXIT WHEN设定退出条件;FOR循环适用于固定次数迭代,WHILE循环基于条件判断执行。有效使用循环能提高效率,但需注意避免无限循环和优化大数据处理性能。掌握循环语句,将使数据处理更加高效和便捷。
|
4天前
|
SQL Oracle 关系型数据库
Oracle的PL/SQL条件控制:数据的“红绿灯”与“分岔路”
【4月更文挑战第19天】在Oracle PL/SQL中,IF语句与CASE语句扮演着数据流程控制的关键角色。IF语句如红绿灯,依据条件决定程序执行路径;ELSE和ELSIF提供多分支逻辑。CASE语句则是分岔路,按表达式值选择执行路径。这些条件控制语句在数据验证、错误处理和业务逻辑中不可或缺,通过巧妙运用能实现高效程序逻辑,保障数据正确流转,支持企业业务发展。理解并熟练掌握这些语句的使用是成为合格数据管理员的重要一环。
|
4天前
|
SQL Oracle 关系型数据库
Oracle的PL/SQL表达式:数据的魔法公式
【4月更文挑战第19天】探索Oracle PL/SQL表达式,体验数据的魔法公式。表达式结合常量、变量、运算符和函数,用于数据运算与转换。算术运算符处理数值计算,比较运算符执行数据比较,内置函数如TO_CHAR、ROUND和SUBSTR提供多样化操作。条件表达式如CASE和NULLIF实现灵活逻辑判断。广泛应用于SQL查询和PL/SQL程序,助你驾驭数据,揭示其背后的规律与秘密,成为数据魔法师。
|
1月前
|
SQL Oracle 关系型数据库
Oracle系列十一:PL/SQL
Oracle系列十一:PL/SQL
|
3月前
|
SQL 缓存 数据库
PL/SQL的性能优化
PL/SQL的性能优化
37 0

热门文章

最新文章