PLSQL程序优化和性能分析方法要点
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
1.前言
1.1目的
性能测试是测试中比较重要的工作,性能测试应分为压力的测试和性能的测试,其中性能问题中绝大部分都是由于程序编写的不合理、不规范造成的。本文档说明了程序中常见的不优化的脚本编写,导致的性能问题,并且在也描述了怎样去跟踪和解决程序上的性能问题的方法。
在最后一章里面描述了做一个白盒测试工具测试性能问题的设计思想。
1.2文档说明
本文档只说明PLSQL 编写的优化问题,不包括ORACLE本身的性能优化(内存SGA、系统参数、表空间等)、操作系统的性能问题和硬件的性能问题。对于PLSQL程序优化方面的内容有很多,本文档列出在我们实际工作中一些常见的情况。本文档难免有不正确的地方,也需要大家给予指正。
本文档举例说明的问题语句不是实际程序中真正存在的,只是让大家能看起来更容易理解,但这些语句也不代表在我们程序中其他部分语句不存在这些问题。
举例说明中的语句采用的是社保核心平台的数据字典,在举例描述中没有标明表名和字
段名的含义,还需单独参考。
1.4参考资料
编号资料名称作者日期出版单位
2.PLSQL程序优化原则
2.1导致性能问题的内在原因
导致系统性能出现问题从系统底层分析也就是如下几个原因:
●CPU 占用率过高,资源争用导致等待
●内存使用率过高,内存不足需要磁盘虚拟内存
●IO 占用率过高,磁盘访问需要等待
2.2PLSQL优化的核心思想
PLSQL优化实际上就是避免出现“导致性能问题的内在原因”,实际上编写程序,以及性能问题跟踪应该本着这个核心思想去考虑和解决问题。
● PLSQL 程序占用CPU的情况
⏹系统解析SQL语句执行,会消耗CPU的使用
⏹运算(计算)会消耗CPU的使用
● PLSQL 程序占用内存的情况
⏹读写数据都需要访问内存
⏹内存不足时,也会使用磁盘
● PLSQL 程序增大IO的情况
⏹读写数据都需要访问磁盘IO
⏹读取的数据越多,IO就越大
大家都知道CPU现在都很高,计算速度非常快;访问内存的速度也很快;但磁盘的访问相对前两个相比速度就差的非常大了,因此PLSQL 性能优化的重点也就是减少IO的瓶颈,换句话说就是尽量减少IO的访问。
性能的优先级CPU->内存->IO,影响性能的因素依次递增。根据上面的分析,PLSQL
优化的核心思想为:
1.避免过多复杂的SQL 脚本,减少系统的解析过程
2.避免过多的无用的计算,例如:死循环
3.避免浪费内存空间没有必要的SQL脚本,导致内存不足
4.内存中计算和访问速度很快
5.尽可能的减少磁盘的访问的数据量,该原则是PLSQL 优化中重要思想。
6.尽可能的减少磁盘的访问的次数,该原则是PLSQL优化中重要思想。
下面的章节具体介绍常见影响性能的SQL 语句情况。
2.3ORACLE优化器
ORACLE的优化器:
a.RULE(基于规则)
b. COST(基于成本)
c. CHOOSE(选择性)
设置缺省的优化器,可以通过对init.ora文件中OPTIMIZER_MODE参数的各种声明,如
RULE,COST,CHOOSE,ALL_ROWS,FIRST_ROWS. 你当然也在SQL句级或是会话(session)级对其进行覆盖.
为了使用基于成本的优化器(CBO, Cost-Based Optimizer) , 你必须经常运行analyze命令,以增加数据库中的对象统计信息(object statistics)的准确性.
如果数据库的优化器模式设置为选择性(CHOOSE),那么实际的优化器模式将和是否运行过analyze命令有关. 如果table已经被analyze过, 优化器模式将自动成为CBO , 反之, 数据库将采用RULE形式的优化器.
在缺省情况下,ORACLE采用CHOOSE优化器,为了避免那些不必要的全表扫描(full table scan) , 你必须尽量避免使用CHOOSE优化器,而直接采用基于规则或者基于成本的优化器.
在oracle10g 前默认的优化模式是CHOOSE,10g默认是ALL_ROWS,我不建议大家去改动ORACLE的默认优化模式。
2.4PLSQL优化
主要说明了在SQL编写上和PLSQL 程序编写上可以优化的地方。
2.4.1选择最有效率的表名顺序
只在基于规则的优化器rule中有效,目前我们oracle 选择的优化器基本都不选择rule,因此该问题基
本不会出现,但为了安全和规范起见,建议编程习惯采用该规则。
ORACLE的解析器按照从右到左的顺序处理FROM子句中的表名,因此FROM子句中写在最后的表(基础表driving table)将被最先处理. 在FROM 子句中包含多个表的情况下,你必须选择记录条数最少的表
作为基础表.当ORACLE处理多个表时, 会运用排序及合并的方式连接它们.首先,扫描第一个表(FROM子
句中最后的那个表)并对记录进行派序,然后扫描第二个表(FROM子句中最后第二个表),最后将所有从第二
个表中检索出的记录与第一个表中合适记录进行合并.
例如:
表ac01有16,384 条记录
表ab01 有1 条记录
选择ab01作为基础表(好的方法)
select count(*)from ac01,ab01 执行时间0.96秒
选择ac01作为基础表(不好的方法)
select count(*)from ab01,ac01 执行时间26.09秒
2.4.2WHERE子句中的连接顺序
ORACLE采用自下而上的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他WHERE 条件之前
例如:
(低效)
SELECT ab01.aab001,ab02.aab051
FROM ab01,ab02
WHERE ab02.aae140=’31’
AND ab01.aab001=ab02.aab001;
(高效)
SELECT ab01.aab001,ab02.aab051
FROM ab01,ab02
WHERE ab01.aab001=ab02.aab001
AND ab02.aae140=’31’;
2.4.3SELECT 子句中避免使用‘*‘
当你想在SELECT 子句中列出所有的COLUMN时,使用动态SQL列引用‘*'是一个方便的方法.不幸的是,这是一个非常低效的方法.实际上,ORACLE在解析的过程中, 会将'*' 依次转换成所有的列名, 这个工作是通过查询数据字典完成的, 这意味着将耗费更多的时间。
2.4.4用EXISTS 替代IN
实际情况看,使用exists替换in 效果不是很明显,基本一样。
在许多基于基础表的查询中,为了满足一个条件,往往需要对另一个表进行联接.在这种情况下,
使用EXISTS(或NOT EXISTS)通常将提高查询的效率.
低效:
SELECT*
FROM ac01
Where aac001in (select aac001from ac02where aab001=str_aab001and aae140=’31’);
或
SELECT*
FROM ac01
Where aac001in (select distinct aac001 from ac02where aab001=str_aab001and aae140=’31’);
注意使用distinct也会影响速度