数据库跑得慢,业务部门催得急,DBA的头发一天比一天少。这事儿我太熟了,干了十几年Oracle运维,见过太多系统从丝般顺滑变成老牛拉破车。其实大部分性能问题都不是什么高深莫测的玄学,就是些基本功没做到位。今天不整那些虚头巴脑的理论,直接上干货,五个招法,都是我在生产环境里实打实验证过的,你照着做,不敢说包治百病,但解决掉八成以上的卡顿问题,问题不大。

第一招,先别急着加硬件,把SQL拿出来晒晒太阳。很多团队一遇到性能瓶颈,第一反应就是“扩容”“加CPU”“加内存”。钱花了一大笔,效果却像是往漏水的桶里倒水。我见过一个客户,系统慢得离谱,领导拍板买了两台新服务器,结果迁移过去照样慢。后来我一查,发现罪魁祸首是一条跑了三秒的SQL,在OLTP系统里被高频调用,一天跑几十万次。你说这跟硬件有啥关系?纯粹是SQL写得烂。所以第一件事,去V$SQLAREA视图里按磁盘读和CPU时间排个序,把那些吃资源的大户揪出来。EXPLAIN PLAN一看执行计划,全表扫描、笛卡尔连接、索引失效,该改改,该加索引加索引。这一招做完,通常能解决掉一半以上的性能问题。
接着第二招,索引不是越多越好,你得学会做减法。很多开发同学有个误区,觉得索引是万能的,见一个查询慢就加一个索引,结果一张表上堆了十几个索引。看起来查询快了,但更新、插入、删除全被拖累,因为每动一条数据,所有索引都得跟着更新。更要命的是,优化器面对一堆冗余索引,反而容易选错执行计划。我处理过一个案例,一张订单表上有八个索引,其中三个字段组合完全重复,纯粹是不同开发人员各加各的。删掉那两个多余的之后,写入性能提升了近四成。所以定期用DBMSSTATS分析一下,再看看V$INDEXUSAGE,把那些半年都没被用过一次的索引,果断DROP掉。做减法,有时候比做加法更有效。
第三招,统计信息别让它过期,这玩意儿比你想的更敏感。Oracle的优化器是个“数据洁癖”,它做任何决定都依赖统计信息。如果表的行数、数据分布这些信息是三个月前的,而你的业务数据早就翻了几番,优化器就会做出离谱的判断——明明有索引不走,偏偏去全表扫描。很多DBA都栽在这上面,排查了半天,发现就是统计信息太旧了。我的习惯是,业务表数据变化超过10%就重新收集一次,核心大表干脆设置自动收集任务,每周跑一次。另外记得用DBMSSTATS的AUTOSAMPLESIZE选项,别手动指定采样比例,那玩意儿很容易出偏差。统计信息新鲜了,优化器才能做出正确的选择,很多莫名其妙的慢查询,就这么自动消失了。
第四招,绑定变量是个宝,但很多人没用对。在OLTP系统里,SQL文本完全一样,只是条件值不同,这种情况就该用绑定变量。如果不绑定,每条SQL都会硬解析,生成独立的执行计划,共享池被撑爆,CPU全耗在解析上了。我见过最夸张的一个系统,共享池命中率不到60%,硬解析每秒几十次,那性能能好才怪。当然,也不是所有场景都适合绑定变量,比如报表系统里那种数据分布极其不均匀的列,绑定变量反而可能让优化器做出错误判断。这时候你可以试试Oracle 11g以后推出的自适应游标共享,或者干脆对特定SQL禁用绑定变量。用不用,用在哪,得根据业务场景来,不能一刀切。
第五招,内存管理没那么玄乎,关键在于别让SGA和PGA打架。Oracle的内存架构,SGA管共享,PGA管私有,两者分工不同。很多老DBA习惯手动设置SGATARGET和PGAAGGREGATETARGET,但设死了之后,一旦业务高峰来了,内存不够用,就会疯狂触发磁盘排序和临时表空间读写,那性能直接崩盘。我建议你如果用的是11g以上的版本,干脆启用自动内存管理,让Oracle自己根据负载动态调配。如果因为特殊原因必须手动设置,那记住一个原则:OLTP系统SGA给大点,PGA满足排序需求就行;OLAP系统反过来,PGA要给足,因为大量的排序和哈希操作都在PGA里做。别把两者搞反了,不然你调多少次参数都是白费。
说到底,Oracle性能优化不是什么屠龙之术,就是把这些基础工作做扎实。SQL写得好,索引用得巧,统计信息保持新鲜,绑定变量用对地方,内存分配合理,这五件事做到了,你的数据库想卡顿都难。我见过太多团队,遇到问题就四处找“神兵利器”,买各种监控工具,请各种外部专家,结果最基本的执行计划都没看过一眼。这就像一个人体重超标,不去控制饮食加强锻炼,反而到处找减肥药,能有用吗?
再啰嗦一句,性能优化不是一次性的事,得当成日常运维的一部分。每个季度抽个时间,跑一遍AWR报告,看看TOP事件,检查一下是否有新的慢SQL出现,统计一下索引使用率。养成这种习惯,你的数据库就能一直保持健康状态。别等问题爆发了才手忙脚乱,那时候不仅费劲,还得背锅。把这五个招法学到手,以后谁再跟你说数据库卡,你心里就有底了——先查SQL,再看索引,统计信息顺手更新,绑定变量检查一遍,内存参数确认无误,一套组合拳下来,问题基本就水落石出了。


