oracle性能优化核心是优化sql、索引和统计信息,而非堆配置或加硬件;80%以上问题源于sql写法、索引缺失或统计信息过期,需通过实时会话定位慢sql、按最左前缀建复合索引、及时更新统计信息、合理使用分区及绑定变量。

Oracle数据库性能优化不是靠堆配置或加硬件解决的,核心在于让SQL少走弯路、让数据少被扫描、让资源不被浪费。绝大多数性能问题,80%以上出在SQL写法、索引缺失或统计信息过期上,而不是参数调优或硬件瓶颈。
怎么快速定位慢SQL?别只看AWR报告
AWR报告有用,但容易滞后;真正要盯的是实时活跃会话和v$session_longops。如果某条SQL执行超过5秒还在跑,它大概率已经卡在全表扫描或大排序上了。
- 用
SELECT sid, serial#, sql_id, event, seconds_in_wait FROM v$session WHERE status = 'ACTIVE' AND event NOT LIKE 'SQL*Net%'查正在堵的会话 -
sql_id拿到后,立刻查v$sql_plan:看有没有TABLE ACCESS FULL出现在大表上 - 别信“执行时间短就没事”——一条
SELECT COUNT(*) FROM big_table可能只花2秒,但它锁住buffer cache、挤占IO,影响的是整个实例
索引建不对,等于没建
建索引不是越多越好,而是要匹配访问路径。常见错误是给WHERE里所有列都建单列索引,结果Oracle一个都没用上。
- 复合索引必须遵循最左前缀:WHERE
status = 'A' AND create_time > SYSDATE-7,索引应为(status, create_time),反过来就失效 - 函数索引要和SQL里写的函数完全一致:WHERE
UPPER(name) = 'JOHN',索引就得是UPPER(name),不能是name或LOWER(name) - 位图索引别乱用:OLTP系统里对
gender建位图索引,一次UPDATE可能锁住整段位图,引发大量enq: TX - row lock contention
统计信息过期比没索引还危险
Oracle 10g以后默认用CBO(基于代价优化器),它全靠统计信息估算行数。如果NUM_ROWS还是三个月前的值,而表已涨了10倍数据,优化器就会选错执行计划——比如该走索引却选了全表扫描。
- 检查是否过期:
SELECT last_analyzed, num_rows FROM user_tables WHERE table_name = 'YOUR_TABLE' - 小表可手动收集:
EXEC DBMS_STATS.GATHER_TABLE_STATS('SCHEMA_NAME', 'TABLE_NAME') - 大表务必加
ESTIMATE_PERCENT => DBMS_STATS.AUTO_SAMPLE_SIZE,否则抽样不准,基数估算全崩 - 千万别用
ANALYZE TABLE ... COMPUTE STATISTICS,这是9i时代的命令,CBO不认它
分区表不是性能银弹,用错反而拖垮DML
分区表对查询有帮助,但前提是你的SQL能自动裁剪(partition pruning)。如果WHERE条件没带分区键,或者用了函数包裹分区列(如TRUNC(part_date)),Oracle照样扫全分区。
- 范围分区+日期字段最稳妥,但注意
INTERVAL分区首次插入时会隐式触发DDL,高并发写入可能卡在library cache lock - LIST或HASH分区适合固定枚举值或均衡分布场景,但跨分区JOIN成本极高,
EXPLAIN PLAN里一旦出现PX COORDINATOR或REMOTE操作符,说明并行打散了 - 分区维护操作(如
DROP PARTITION)会产生大量归档日志,别在业务高峰做;TRUNCATE PARTITION比DELETE快,但会重置高水位线,后续INSERT可能触发大量块分配
最容易被忽略的一点:绑定变量不是万能解药。当WHERE条件列的数据分布极度倾斜(比如status里99%是'ACTIVE',1%是'ERROR'),即使用了绑定变量,硬解析少了,但执行计划还是错的——因为优化器按平均分布估算,实际走索引对'ERROR'快,对'ACTIVE'反而慢。这时候得考虑SQL Profile或自适应执行计划,而不是反复改SQL。











