当前位置: 代码迷 >> SQL >> Oracle PLSQL调优中的几个小问题
  详细解决方案

Oracle PLSQL调优中的几个小问题

热度:110   发布时间:2016-05-05 14:43:31.0
Oracle PLSQL调优中的几个问题

尽管不是DBA,但在系统调优的工作中还是涉及了不少数据库方面的工作,主要是Oracle PLSQL的优化。这里做个简单的备忘(由于没有系统地研究过,有些解释带有猜测的成分)。

?

1. 应该使用绑定变量

?

第一次执行sql时,会进行硬解析(生成解析树及执行计划等),这些操作会消耗一定的系统资源,接着再把解析后的sql放入缓冲池(SGA中),这个会涉及latching(一种保护共享内存区中数据的机制),造成等待(后者可能比前者更影响性能)。如果sql进入了缓冲池,以后再使用这条sql时,只需要做语法、语义检查、权限检查以及软解析(缓冲池命中等)等。使用绑定变量,可以减少相似的sql大量占用缓冲池空间,降低硬解析的发生。

?

补充:

1.1 大小写也会影响sql的hash value,这会导致shared pool中statement key的不同,从而增加了硬解析的可能性。所以,sql的规范书写也需要注意。

1.2 latch类似于lock,但与lock不同的是,它不是一个queue。在获取latch的时候,会发生spinning(轮询),从来带来CPU的开销,轮询次数取决于参数_spin_count,当到达这个轮询次数时,这个session会放出cpu的使用权,等待下次的竞争。

1.3 在硬解析过程中,其中的一项工作是查询59张系统表,相比于软解析,其性能开销惊人。

1.4 软解析也需要读shared pool,但只是读,而硬解析既需要读,也需要写,这就是为什么会涉及latching的道理。恐怖的是,latching是个串行化的操作,一个instance中只有一个shared pool:(

?

2. 应该使用bulk collect和forall

?

在PLSQL中,当处理涉及到多行的sql时,要使用bulk处理。这可以减少PLSQL engine和SQL engine之间的切换。当多行的数量达到一定规模时,这种切换对性能影响还是很大的。使用bulk处理,可以把context切换降到一次,这无疑是一种值得推荐的方法。

?

3. 在对性能要求比较高的情况下,使用静态sql

?

execute immediate使用起来很方便,但它执行的是本地动态sql(NDS),需要一次动态解析的过程。如果你一定要使用动态sql,可以使用DBMS_SQL,它提供手工控制解析的方法,这样,在肯定不需要多次parse的时候,只parse一次就可以了。不过,在对性能要求比较高的情况下,还是使用静态sql最理想。

?

4.? 使用PLSQL提供的各种Cache机制

?

要从根本上提升性能,使用cache是王道。PLSQL提供了基于包的缓存,函数结果集缓存等,要充分使用起来。

?

5.? 使用pipelined表函数

?

pipelined表函数的基本思路是,在函数执行过程中就返回记录,而不用等函数全部执行完,再返回到calling context。这个好处是减少了大量的PGA使用,换句话说,节省了内存的分配和使用。这在传输大数据量的时候,对于性能的提升特别有效。而且,pipelined表函数还可以使用parallel处理。

?

6. SQL优化

?

一定要多看执行计划,很多性能问题可以扼杀在摇篮里。避免全表扫描,除非这永远是张小表。index要规划好,不要建得太多,外键要建索引,避免任何可能导致锁表的情况出现,使用正确的数据类型,对于OLTP,sql要尽可能地简单(数据模型要建好),要考虑数据分布等等,总之,要下很多功夫。

?

补充:

6.1 在大多数情况下,全表扫描是低效的,但也不可一概而论。查询数据的性能取决于两点,一个是看要读取多少block,一个是看每个读取的block中要丢掉多少数据。这两点和数据的物理分布有关,在某些极端的情况下,访问一张表中极少比例的记录(读取大量的block),使用全表扫描的性能也比用索引要好,事实上,oracle的优化器会帮你这么做,但是,当另一个因素——每个读取的block要过滤掉多少数据——发生作用时(如果大量的数据要丢掉),oracle的优化器又可能会帮你切换到使用索引的执行计划。你可以使用hints来影响优化器的行为,前提是你真的要知道自己在干什么。哈。不过,如果出现这里说的情况,所谓的好,也已经都非常不好了。

6.2 即使Oracle的优化器选择了全表扫描,也可能是一个错误的选择,因为全表扫描会和highwater mark有关,当大量的数据被Delete之后,highwater mark不会复位,而全表扫描会去读那些空的block,这会带来不必要的性能问题。

6.3 为什么说有时候全表扫描比索引快呢?因为,全表扫描是一次读取多个block,而索引是一次读取一个block(为了得到一条记录,至少要读两次,一次是index block,一次是data block)。假设db_file_multiblock_read_count是16,而表中有16条记录,highwater mark也就在这里,现在要拿到这16条记录,用全表扫描,只需要读一次;而用索引,则至少32次。当然,实际案例要复杂得多。无论如何,简单说孰优孰劣是不行的。

?

7. 批处理要采用特殊的手段

?

尽量找到反复使用同一条sql对同一张表操作的机会,这可以使用到很多oracle中的缓存机制。

?

8. 调整Oracle系统参数

?

在万不得已的情况下,去调整一些系统参数。比方说,arraysize,可以降低fetch的网络往复和逻辑读的次数,之类的,我不是dba,了解得不是太多。

?

9. statistic分析

?

专业的、优秀的DBA会给你精彩的解释,如果碰到这样的dba,也许你会爱上oracle。。。

?

  相关解决方案