El Psy Congroo

ORACLE RWP性能之旅杭州站活动记录

周末参加了CN’SOUG组织的ORACLE RWP性能之旅杭州站活动,演讲嘉宾是Oracle RWP的VP Andrew Holdsworth以及架构师Graham Wood,两位都是有30年Oracle从业经验的大牛,讲的内容虽然不深,但是听大师从宏观层面过一遍性能优化的方法论,还是挺有收获的,凭印象简单做个笔记。

目标

性能调优的目标是1000X

方法

性能调优不存在魔法,完全依靠数据驱动(Data-driven),因此首先需要全面的监控,包括应用时间,数据库时间,网络round-trip时间,根据监控找到调优收益最高的点,即leverage,这个词贯穿了一天的演讲。

调优方法有Top-down和Bottom-up两种,前者是开发人员常用的方法,根据监控从应用层开始自顶向下进行优化,后者是性能专家常用的方法,从硬件架构开始寻求性能的改善点。在真实运行环境中,大部分性能问题都是由业务系统不正确的使用数据库,以及业务数据走错执行计划造成的,因此采用Top-down方式更有利于我们达成1000X的调优目标

SLA

每个系统都应该定义SLA(Service-level agreement),作为我们查找性能问题的参考基准。否则出现问题时,常常会引起自上而下层层blame,应用说DB问题,DB说存储问题,存储说给钱换PCIe… 如果每层都有SLA,例如DB的tps,响应时间都在SLA内,那基本就可以排除DB问题。

AM

上午的演讲过程中,主讲人用live demo的方式,通过几个case,让我们直观的感受到错误使用姿势给数据库带来的性能影响,不过其中很多点对于开发人员来说已经是耳熟能详的了

Case 1 设置合理的最大连接数量

随着每cpu内核对应的进程数的提高,增加cpu数量反而会导致tps下降,原因是线程切换及竞争带来的大量性能开销,从live demo中可以看到,进程数过高时,服务器几乎处于无响应状态
<此处应有图,等拿到ppt补上…>
1/10/50 processes/core

另外要注意物理内核(core)和线程(thread)的区别,例如E5-2690V3是12核24线程。Intel每个内核上有两个线程,通过多个线程共享一个内核的方式有利于提升cpu的利用率,但是操作系统在报告cpu数量(实际是线程数)及利用率时,会带来一定的迷惑性。实际使用时,根据应用的类型的不同,双线程带来的性能提升(相对于每个内核上一个线程)也会有区别,例如对于OLTP,提升大约是30%

Case 2 合理使用连接池

在这个case里,数据库cpu占用率较高,tps和响应时间都很低,从监控中发现每秒登陆数有几百次。问题原因是应用没有使用连接池,并且有大量短事务请求,导致开销都在连接建立上。这个坑以前有踩过类似的,一个系统上线时连接池使用了测试环境的配置,dbcp的maxIdle配置的过低,导致频繁的断开/重建连接建立占用了大量cpu sys time

Case 3 解析

通过绑定变量减少cpu开销(软解析),同时防止sql注入

Case 4 Leaking

Cursor Leaking
ORA-010000 maximum open cursors exceeded
这个坑很多开发都踩过,一般都是statement没有及时关闭。我们以前在MyBatis3.1中也遇到过这个问题,SelectKeyGenerator中存在bug,导致insert前selectKey打开的statement没有关闭,在大批量insert的事务中就会出现这个报错

Connection Leaking
由于程序异常导致的连接没有关闭/归还连接池,除了资源占用外,还可能导致部分被锁定的资源没有释放,阻塞了其他sql的执行,需要dba干预kill连接。不过连接池的removeAbandon功能应该可以避免这类问题吧。

PM

下午的演讲主要关注AWR,数据库参数,以及执行计划

AWR案例分析

过了一份AWR报告,分析出几个问题。AWR了解不多,而且投影字太小完全看不清=.=
从session数量看貌似有泄露?这个不是很理解=.=
大量的select 1 from dual,连接池testOnXXX产生的。貌似这个在我们生产环境中虽然调用次数很多,但是没什么开销
select for update产生的大量行锁
in不定长参数列表产生大量相似的SQL解析。这个生产环境很常见,感觉1000以下的都能接受,最多硬解析1000次… 再多我们就考虑临时表join了

在init.ora中使用默认值

尽量使用默认参数,没有特别的理由以及数据支持不要修改。默认参数是Oracle包括优化器开发及测试时使用的参数,在大部分情况下能得到最优的性能,出现问题时,也最容易得到支持。

统计信息

采集例如表中记录数,列最大最小值,唯一值数量,直方图(histogram)等,作为CBO选择最优执行计划的依据

执行计划优化案例

通过EM中的SQL Monitor找到开销最大的位置进行优化,下面几个案例甚至都不需要看完整的SQL,直接分析问题点就能找到原因

Case 1

parallel hash join时,驱动表被broadcast到所有工作线程,实际上驱动表非常大,并不适合broadcast

问题原因是低估了驱动表的cardinality,过滤驱动表的查询条件存在数据关联,如prov='ZJ' and city='HZ' and county='XIHU',优化器会将三个字段的选择度相乘,认为结果数据集很小,实际上结果数据主要是由最后一个字段决定的
从这里我们可以看出领域知识(Domain knowledge)在优化过程中的重要性。解决方式也很简单,将存在关联的字段一并采集统计信息

Case 2

选择了错误的join方式

问题原因仍然是错误估算了cardinality,查询条件中对字段使用了函数,因此无法使用统计信息,优化器猜测的值实际是低估了,导致走了nested loop。解决方式是尽量避免查询时使用函数,像是将多个值编码到一个字段中,查询时通过substr拆分这种模式尤其要避免。无法避免时,对字段带函数收集统计信息。

Case 3

parallel hash join时,任务分布不均,近半任务落在一个工作线程上

这次的cardinality估算是正确的,问题原因在数据上,这里的hash key是会员卡号,但是当用户没有会员卡时,这个字段的值为-1,大部分用户没有会员卡,导致大量数据hash到了同一个工作线程上。解决方式是将有会员卡和没有会员卡的拆分为两个查询。这里又一次强调了领域知识的重要性。

Important idea

演讲的最后,Andrew分享了一个idea

当别人给你性能解决方案但没有给你理由时,要敢于追问为什么,要求数据支持,直到你完全理解为止。
当你做性能调优决策时,不能仅靠猜测,必须要有数据证明。
Location, Location, Location Data, Data, Data