oracle数据库性能优化案例分析及最佳实践

1 案例分析

案例一:Library cache lock等待

问题背景:

严重的Library cache lock等待,导致SQL执行的很慢
在这里插入图片描述

问题分析:
Library cache lock等待常见场景:

  1. DDL、统计信息搜集
    Namespace→1:table/view/sequence/synonym/
  2. 错误密码登陆
    Namespace→79:Account status
  3. FailureParse
    Namespace→82:SQL AREA BUILD
  4. ADG
    Namespace→74:DBINSTANCE

在这里插入图片描述

案例二:row cache lock等待

问题背景:

大量的row cache lock等待事件,导致数据库夯住。

问题分析:
从dba_hist_active_sess_history中分析看到,数据库于17:30:28开始出现row cache lock(dc_user),从中可以看到,1号节点的会话4901阻塞了3052,4901是一个sqlplus程序,在执行grant object操作。

分析数据库audit日志XXXX1_ora_25757616_1.aud如下:
在这里插入图片描述
因为这个系统业务期间每个节点每秒大概有5、6次的login,两个节点加起来每秒大概有10到12次的login。在因此导致了大量的row cache lock等待事件。

DC_USERS This may occur if a session issues a GRANT to a user and that user is in the process of logging on to the database. Investigate why grants are being made while the users are active.

解决方案:
避免在业务期间进行grant/revoke操作。

案例三:truncate大表

问题背景:

扫描二维码关注公众号,回复: 9779996 查看本文章

truncate大表,导致业务等待资源释放,进而数据库服务器连接数太多导致崩溃

问题分析:
在表的truncate的操作没有完成的情况下,所有的INSERT操作都被挂起了。然后由于这个INSERT操作又是应用程序的日志记录操作,所以造成了大部分客户化的应用程序都因为等待日志表的写而挂起。

ASH记录中,有2000多个6zx4a78zj3963(Insert CUX_0_WS_INVOKE_LOG)都执行了20分钟以上。

分析原因,可能是除了Truncate进程,其他排队的进程基本都是6zx4a78zj3963。因为6zx4a78zj3963数量非常多,但是又因为Truncate在前,Insert执行不了。到Truncate终止,Insert语句才开始执行。

注:检查了6zx4a78zj3963的执行数量,从5月27日10:11到5月30日14:45,一共76.5小时,一共执行了月500万次,平均每小时6.5万次,每分钟超过1000次。尽管每次连接不只写入一条记录,保守估计,以每次连接写入10条记录来算,每小时的连接数也有6500次。因此,Truncate语句如果40多分钟没有执行完成,堵住的Insert语句就有可能超过最大进程数5000。

解决方案:
Truncate大表的时候,虽然不写日志,但因为要回收空间,所以也是会有性能问题的。对于有CLOB字段的表,Truncate的性能就有点类似Delete了。另外,索引的存在,也会影响Truncate的性能。

Truncate大表,虽然手工终止,但是数据库后台还在继续释放资源,这个过程可能持续20分钟之久。

建议将表按时间分区,并定期清理。清理时,直接Drop掉不再需要的历史分区即可。但使用分区表时也要注意,尽量不要有全局索引。如果有全局索引,无论是Truncate分区还是Drop分区,都会造成全局索引失效,需要重建索引。

Truncate大表时,可以结合使用reuse storage来提高性能。

通常认为,Truncate和Drop都是ddl语句,都会释放表占用的空间,且不可回退。这是因为Truncate默认使用的是drop storage,Truncate的同时会立即释放extent,删除的表如果非常大,就会有很明显的性能问题。如果使用reuse storage的话,是不会立即释放表的extent的,性能就会好很多。

具体做法是先使用如下Truncate语句:

Truncate table tableName reuse storage;

然后,再分批释放空间:

ALTER TABLE BIGTAB DEALLOCATE UNUSED KEEP 4096M;
ALTER TABLE BIGTAB DEALLOCATE UNUSED KEEP 2048M;
ALTER TABLE BIGTAB DEALLOCATE UNUSED KEEP 1M;

对于LOB字段和索引,也可以采用同样的方式逐步回收:

ALTER TABLE  MODIFY LOB() DEALLOCATE UNUSED KEEP xxxM;
ALTER INDEX  DEALLOCATE UNUSED KEEP xxxM;

案例四:统计信息收集不及时

问题背景:

统计信息收集不及时,导致执行计划变了,有一个sql,一段时间比较快,一段时间比较慢。

问题分析:
这个sql_id的执行计划主要有两个,Plan Hash Value分别是2716755970和256938306。
在这里插入图片描述
像这种情况,建议直接通过SQL Profile绑定执行计划,使其固定使用Plan Hash Value = 2716755970的执行计划。

为什么会出现两个效率明显差异的执行计划交替使用呢?我们认为应该跟表的统计信息有一定的关系。

这个sql中用到的几个大表,MTL_MATERIAL_TRANSACTIONS的统计信息是2018/5/5的,表OE_ORDER_HEADERS_ALL的统计信息是2018/2/5的,但表OE_ORDER_LINES_ALL的却是2018/5/26的。这种直接关联的表,统计信息日期相差太大的话,会出现不匹配的现象。如果查询的条件刚好覆盖到最新一部分数据时,就会造成有的表有该部分数据的统计信息,但有的表却没有的情况。这时CBO就会认为两表关联结果为0,出现误判。

案例五:乱加并行度,会话数暴增

问题背景:

有些SQL,占用Session数很多,比如下面的7vuhb2tb6jwj9
在这里插入图片描述

问题分析:
从等待事件看,这些Session都是等待PX相关事件,说明这些都是并行执行的Slave Session,但整个SQL里并没有添加Parallel提示,怀疑是某个表或者索引的Degree大于1。

检查发现,一些表重建索引的时候加了并行,但是事后没有将并行去掉。
一个sql,消耗太多Session,就会造成资源浪费,并有可能导致连接数不够,影响其他用户登录。

而且,如果不是Index Full Scan,而是Index Range Scan或者Index Unique Scan等的话,并行扫描是完全不会提高性能的。几乎没有哪个表或者索引,启用并行扫描一定就会快。一定要根据具体的执行计划才能决定是否需要加并行。因此,在表上或者索引上设置Degree大于1是不提倡的。可以根据需要在相应的SQL语句上加并行提示。

另外,视图创建脚本上,也不需要加并行提示。

案例六:SQL未加绑定变量

问题背景:

大量SQL未加绑定变量,导致共享池资源争用严重,从而引发数据库资源不足,导致hang。
在这里插入图片描述
SQL解析命中率:
Library Hit %: 72.53 Soft Parse %: 52.59
共享池大小抖动情况:(SGA_TARGET = 7168M)
MIN_SIZE MAX_SIZE CURRENT_SIZE
1120M 6048M 1384M

问题分析:
应用系统中存在大量SQL语句未使用绑定变量,导致共享池的争用严重,共享池的严重争用导致相关事件的等待时间变长,数据库响应变慢。

当系统处于业务高峰,数据库会话数急剧增加,操作系统内存耗尽,出现了严重的换页现象,最终导致数据库hang。

案例七:SQL语法不规范

问题背景:

SQL语法写法不规范,造成PGA耗用较大且不释放。
现象:收到监控系统反馈,一个Linux系统上的RAC数据库的内存耗用较多,swap空间也使用较多。

问题分析:

  1. 按照操作系统命令,对内存使用情况的进程进行排序。

    ps -aux | sort -k4nr | head  -20
    
  2. 对排名靠前的会话进行分析,且分析awr报告,发现内存耗用都是在PGA上。

  3. 对排名靠前的会话进行采用heapdump分析。

    # 数据库heapdump命令.
    oradebug setospid 108856
    oradebug unlimit
    oradebug dump heapdump 5
    oradebug tracefile_name
    
  4. 对trace文件分析解读,发现超过90%的内存耗费在top uga heap段的qmxdpls_subheap部分。

    EXTENT 8 addr=0x7fe877963030
    Chunk 7fe877963040 sz= 2072 freeable  "qmxdpls_subhea "  ds=0x7fe8bc0ce278
    Chunk 7fe877963858 sz= 4264 freeable  "qmxdpls_subhea "  ds=0x7fe8bc0ce278
    Chunk 7fe877964900 sz= 4184 freeable  "qmxdpls_subhea "  ds=0x7fe8bc0ce278
    Chunk 7fe877965958 sz= 4264 freeable  "qmxdpls_subhea "  ds=0x7fe8bc0ce278 
    
  5. 对qmxdpls_subhea进行分析,此部分是由解析xml时使用的,初步怀疑问题点是在程序调用xml时造成内存泄漏。

  6. 为了进一步对初步判断的点进行更深入的程序分析,定位找到相应的代码

    select PGA_ALLOC_MEM/1024/1024/1024 GB,a.spid,b.machine,b.program,b.sql_id,b.event,b.status
    from v$process a,v$session b
    where a.addr=b.paddr and PGA_ALLOC_MEM/1024/1024/1024>1
    order by 1;
    

    发现多个进程耗用PGA 4G,且都是一个sql_id,直接杀掉这些进程,释放部分空间,可是过一会,又起来了。

  7. 分析sql代码,找到发现调用xml解析的点。

    代码里面有一段:XMLDOM.OPENDOCUMENT,上MOS进行查询,Oracle对此语句的写法有建议:

    调用后,用XMLDOM.FREEDOCUMENT 释放内存。

  8. 通知开发,对此sql进行修改,按照官方建议整改,后续监控发现,没有该问题发生。

2 数据库性能最佳实践

2.1 使用连接池

当数据库操作和访问频繁的时候,使用连接池可以减少创建连接和打开连接所耗的时间,提升数据库服务器的性能。

2.2 绑定变量减少硬解析

硬解析消耗大量的CPU时间和系统资源。硬解析过多会降低系统性能。

2.3 业务高峰期,尽量避免实行DDL

• 一个简单的GRANT语句都可能会引起性能问题。
• 执行DDL后会引起相关的SQL在共享池中的失效。
  当相关SQL再次并发执行,可能会导致硬解析风暴。从而引起"library cache lock", "row cache lock", "cursor: pin S wait on X"以及相关latch的等待。

2.4 数据库服务器上部署OSWatcher

完善的监控有助于提前发现性能问题,并且在出现性能问题时快速定位瓶颈。

2.5 定时搜集统计信息

• 优化器并不完美。
• 优化器有效的补充:
	(1)SQL Tuning Advisor
	(2)SQL Plan Baseline
	(3)SQL Profile
	(4)SQL Patch
	(5)SQL 书写优化

2.6 按时应用PSU/RU

定时打补丁,有助于提高数据库安全性及性能。

2.7 使用AWR基线

在这里插入图片描述
在这里插入图片描述

发布了6 篇原创文章 · 获赞 9 · 访问量 7105

猜你喜欢

转载自blog.csdn.net/zhengide/article/details/104779857