Oracle学习专栏(五):性能优化
文章目录
- 前言
- 一、执行计划深度解析(EXPLAIN PLAN/AUTOTRACE)
- 1.1 优化器工作流程
- 1.2 获取执行计划的四种方法
- 1.3 执行计划关键指标
- 1.4 执行计划陷阱识别
- 二、SQL调优技巧:索引策略与提示符
- 2.1 索引策略:构建高效数据访问路径
- 2.2 提示符(Hints):精准引导优化器
- 2.3 索引与提示符实战案例
- 三、等待事件分析(v$session_wait)
- 3.1 等待事件核心概念
- 3.2 v$session_wait 视图
- 3.3 等待事件诊断与优化
- 3.4 从等待事件到解决方案
- 四、AWR报告解读
- 4.1 核心概念和作用
- 4.2 ADDM建议模块
- 4.3 5步定位性能瓶颈
- 结语
前言
性能优化是数据库管理的核心任务。本文深度解析Oracle性能优化的四大关键领域:执行计划解读、SQL调优技巧、等待事件分析及AWR报告实施,结合代码示例与图形解析,助你精准定位瓶颈。
一、执行计划深度解析(EXPLAIN PLAN/AUTOTRACE)
执行计划是Oracle优化器生成的SQL执行路线图,它决定了SQL如何访问数据、处理连接和排序操作。理解执行计划是SQL优化的基础。
1.1 优化器工作流程
优化器基于成本模型(Cost-Based Optimizer) 选择计划,成本单位是逻辑I/O次数。
1.2 获取执行计划的四种方法
- EXPLAIN PLAN(静态计划):EXPLAIN PLAN是Oracle提供的静态分析SQL执行路径的方法,它通过生成逻辑执行计划帮助预测SQL性能表现,而无需实际执行SQL语句。
-- 生成执行计划
EXPLAIN PLAN FOR
SELECT e.last_name, d.department_name
FROM employees e
JOIN departments d ON e.department_id = d.department_id
WHERE e.salary > 10000;-- 显示计划
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY());
- AUTOTRACE(SQLPlus专用):AUTOTRACE是SQLPlus提供的自动跟踪功能,可显示SQL执行计划和统计信息。
SQL*Plus 是 Oracle 公司提供的交互式命令行工具,用于与 Oracle 数据库进行交互和管理。作为 Oracle 数据库的标准接口工具,它允许用户执行 SQL 语句、PL/SQL 块以及管理数据库对象。
配置步骤:
1.运行utlxplan.sql脚本创建PLAN_TABLE。
2.运行plustrce.sql脚本创建角色plustrace。
3.将角色plustrace授予用户。
SET AUTOTRACE TRACEONLY EXPLAIN; -- 仅显示计划
SET AUTOTRACE ON; -- 显示结果+计划
- 实时执行计划(v$sql_plan)
-- 先执行SQL
SELECT /*+ MONITOR */ * FROM employees WHERE department_id = 60;-- 查询计划
SELECT *
FROM v$sql_plan
WHERE sql_id = (SELECT sql_id FROM v$sql WHERE sql_text LIKE '%MONITOR%');
- SQL Monitor(11g+ 图形化监控):Oracle SQL Monitor 是 Oracle 数据库企业版提供的实时 SQL 监控工具,用于动态捕获和分析正在执行的 SQL 语句的性能特征和执行计划。
SELECT DBMS_SQL_MONITOR.REPORT_SQL_MONITOR(sql_id => 'g8ruhm9sxz3tk',type => 'TEXT'
) AS report
FROM dual;
1.3 执行计划关键指标
基础指标定义与解读:
- Operation:操作类型,描述数据库执行的具体操作,如TABLE ACCESS FULL(全表扫描)、INDEX RANGE SCAN(索引范围扫描)等。
- Rows(Cardinality):优化器估算的当前操作返回的行数,基于统计信息计算得出。
- Bytes:执行该步骤后返回的字节数,反映操作处理的数据量。
- Cost:优化器估算的执行成本,包含CPU和I/O开销,理论上越小越好。
- Time:Oracle估计的当前操作所需时间。
- TempSpc:预估操作使用临时表空间的大小,用于排序、哈希连接等内存密集型操作。
指标间数学关系:
执行计划中各关键指标存在紧密的关联关系:
- Cost计算:Cost = I/O cost + CPU cost,其中%CPU表示CPU成本占总Cost的百分比。
- Cardinality估算:基数=表行数×选择率,选择率计算准确性直接影响执行计划质量。
- Bytes与Rows关系:Bytes ≈ Rows × 平均行长度,反映数据吞吐量。
1.4 执行计划陷阱识别
- 统计信息失真
-- 检查估算行数 vs 实际行数
SELECT /*+ GATHER_PLAN_STATISTICS */ * FROM orders WHERE status = 'SHIPPED';-- 对比报告
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(null,null,'ALLSTATS LAST'));
DBMS_XPLAN.DISPLAY_CURSOR 是 Oracle 数据库提供的关键性能诊断工具,用于显示库缓存中SQL语句的实际执行计划,与预估执行计划工具不同,它直接从共享池获取已执行SQL的真实运行时信息。
当A-Rows(实际行数)与E-Rows(估算行数)差异>10倍时,需更新统计信息:
EXEC DBMS_STATS.GATHER_TABLE_STATS('SCOTT','ORDERS');
- 隐式类型转换
-- 执行计划显示
filter(TO_NUMBER("PHONE")=123456) -- 索引失效!
解决方案:
ALTER TABLE customers MODIFY phone VARCHAR2(20); -- 统一类型
使用DBMS_XPLAN.DISPLAY_CURSOR获取实际执行计划比EXPLAIN PLAN更准确,因为它包含运行时信息。定期使用DBMS_STATS收集统计信息是保持执行计划稳定的基础。
二、SQL调优技巧:索引策略与提示符
2.1 索引策略:构建高效数据访问路径
- 索引类型与适用场景
索引类型 | 适用场景 | 创建示例 | 注意事项 |
---|---|---|---|
B-Tree索引 | 高选择性列(主键、唯一键) | CREATE INDEX idx_emp_id ON emp(emp_id); | 默认索引类型 |
位图索引 | 低基数列(性别、状态码) | CREATE BITMAP INDEX idx_gender ON emp(gender); | 仅适用于OLAP系统 |
函数索引 | 列参与函数运算的查询 | CREATE INDEX idx_upper_name ON emp(UPPER(last_name)); | 维护成本高 |
复合索引 | 多列组合查询 | CREATE INDEX idx_dept_job ON emp(dept_id, job_id); | 遵循最左前缀原则 |
反向键索引 | 缓解索引热点块(如序列主键) | CREATE INDEX idx_emp_id_rev ON emp(emp_id) REVERSE; | 范围查询失效 |
- 索引设计原则
- 选择性原则:索引选择性 = 不同值数量 / 总行数。
建议:选择性 > 0.1 的列才适合建索引。 - 最左前缀原则(复合索引)。
- 避免冗余索引。
- 选择性原则:索引选择性 = 不同值数量 / 总行数。
- 索引失效的七大陷阱与解决方案
失效场景 | 示例 | 解决方案 | 执行计划表现 |
---|---|---|---|
隐式类型转换 | WHERE emp_id = ‘100’ (数字列) | 统一类型:WHERE emp_id = 100 | TABLE ACCESS FULL |
索引列参与运算 | WHERE salary*1.1 > 5000 | 改写:WHERE salary > 5000/1.1 | FILTER 操作 |
前导通配符查询 | WHERE name LIKE ‘%SON%’ | 使用反向函数索引 | TABLE ACCESS FULL |
NOT 或 <> | WHERE status <> ‘ACTIVE’ | 改用 OR 或位图索引 | FULL SCAN |
IS NULL 判断 | WHERE commission IS NULL | 创建函数索引:NVL(commission,0) | TABLE ACCESS FULL |
OR 条件未覆盖 | WHERE dept=10 OR job=‘MANAGER’ | 创建复合索引或UNION ALL | CONCATENATION |
统计信息过时 | 索引存在但未使用 | 更新统计信息 | 成本估算偏差大 |
2.2 提示符(Hints):精准引导优化器
Oracle Hint是嵌入在SQL注释中的特殊指令,用于向优化器提供执行计划的指导建议,格式为/*+ hint */或–+ hint。它不是强制命令,优化器会根据实际情况决定是否采纳。
- 提示符语法规范
SELECT /*+ HINT_NAME(参数) */ ... -- 必须紧接SELECT后
FROM table_name;
关键规则:
- Hint必须放在/*+ … */注释中,+号必须紧跟在/*后面。
- 多个Hint可以组合使用,用空格分隔。
- Hint对大小写不敏感,必须紧跟在SELECT/UPDATE/DELETE等关键字后。
- 核心提示符分类解析
访问路径提示符:
提示符 | 作用 | 使用场景 | 示例 |
---|---|---|---|
INDEX(table idx) | 强制使用特定索引 | 优化器选择了低效索引 | SELECT /*+ INDEX(emp idx_emp_dept) */ … |
FULL(table) | 强制全表扫描 | 小表或需要全扫描的特殊场景 | SELECT /*+ FULL(emp) */ … |
INDEX_FFS(table idx) | 快速全索引扫描 | 仅需索引列且数据量大 | SELECT /*+ INDEX_FFS(emp idx_emp) */ … |
连接方式提示符:
-- 嵌套循环连接(小表驱动)
SELECT /*+ USE_NL(orders customers) */ *
FROM orders JOIN customers USING(customer_id);-- 哈希连接(大数据集等值连接)
SELECT /*+ USE_HASH(emp dept) */ *
FROM emp JOIN dept ON emp.dept_id = dept.dept_id;-- 排序合并连接(有序数据集)
SELECT /*+ USE_MERGE(orders order_items) */ *
FROM orders JOIN order_items USING(order_id);
连接顺序提示符:
-- 强制连接顺序:dept → emp → jobs
SELECT /*+ LEADING(dept emp jobs) */ dept.dname, emp.ename, jobs.job_title
FROM dept
JOIN emp ON dept.dept_id = emp.dept_id
JOIN jobs ON emp.job_id = jobs.job_id;
并行执行提示符:
-- 指定并行度4
SELECT /*+ PARALLEL(emp 4) */ * FROM emp;-- 禁止并行
SELECT /*+ NO_PARALLEL(emp) */ * FROM emp;
2.3 索引与提示符实战案例
案例1:复合索引优化分页查询
问题SQL:
SELECT * FROM (SELECT /*+ INDEX_FFS(orders)*/ orders.*, ROWNUM rn FROM orders WHERE customer_id = 100 ORDER BY order_date DESC
) WHERE rn BETWEEN 101 AND 120;
优化步骤:
- 创建复合索引:
CREATE INDEX idx_cust_orders ON orders(customer_id, order_date DESC);
- 添加提示符:
SELECT /*+ INDEX(orders idx_cust_orders) */ ...
案例2:函数索引优化日期查询
低效查询:
SELECT * FROM sales
WHERE TRUNC(sale_date) = DATE '2023-01-01'; -- 索引失效
优化方案:
- 创建函数索引:
CREATE INDEX idx_trunc_saledate ON sales(TRUNC(sale_date));
- 使用提示符:
SELECT /*+ INDEX(sales idx_trunc_saledate) */ *
FROM sales
WHERE TRUNC(sale_date) = DATE '2023-01-01';
调优策略:
三、等待事件分析(v$session_wait)
3.1 等待事件核心概念
Oracle等待事件(Wait Event)是数据库系统中关键的性能指标,用于描述会话在执行SQL语句过程中等待某些资源或条件的时间。当会话无法立即获得所需资源时,Oracle会将其置于等待状态,并记录:等待类型(事件名称),等待时长,等待资源标识,阻塞者信息。
等待事件分类:
类别 | 占比 | 典型事件 | 优化方向 |
---|---|---|---|
User I/O | 40% | db file sequential read | SQL优化/缓存/存储 |
Concurrency | 25% | enq: TX - row lock contention | 事务设计/锁优化 |
Configuration | 15% | latch: shared pool | 内存调整/游标共享 |
Commit | 10% | log file sync | 提交频率/日志写入优化 |
Network | 5% | SQL*Net message to client | 网络延迟/应用设计 |
Idle | 5% | SQL*Net message from client | 通常忽略 |
3.2 v$session_wait 视图
关键字段解析:
SELECT sid, event, wait_time, seconds_in_wait, state,p1, p2, p3, -- 事件特定参数blocking_session,blocking_session_status
FROM v$session_wait
WHERE wait_class != 'Idle'; -- 过滤空闲事件
- event:等待事件名称(诊断核心)
- state:
- WAITING:当前正在等待
- WAITED UNKNOWN TIME:历史等待(无计时)
- WAITED SHORT TIME/WAITED KNOWN TIME:历史等待(有时长)
- wait_time:
- 0:当前正在等待
- | 0:上一次等待时间(厘秒)
- seconds_in_wait:当前等待已持续秒数(对state=WAITING有意义)
- p1, p2, p3:事件参数(需结合v$event_name解读)
- blocking_session:阻塞会话的SID(锁争用关键)
v$session_wait是Oracle数据库中关键的性能诊断视图,用于实时监控会话的等待事件情况。它记录了每个会话当前正在等待或最近完成的等待事件详细信息,是Oracle性能调优的重要工具
3.3 等待事件诊断与优化
- db file sequential read(单块读)
本质:索引访问/表通过ROWID访问时单块I/O。
优化方案:
具体措施:
检查热点段:SELECT * FROM v$segment_statistics WHERE statistic_name=‘physical reads’;
优化SQL减少逻辑读:索引优化、避免回表。
- enq: TX - row lock contention(行锁竞争)
诊断:
-- 查找锁持有者
SELECT sid, sql_id, blocking_session
FROM v$session
WHERE blocking_session IS NOT NULL;
解决方案:
应用层:缩短事务时间,及时提交
数据库层:SELECT … FOR UPDATE NOWAIT。
该语句的主要功能是在查询数据时立即尝试获取行级排他锁,如果目标行已被其他事务锁定,则立即返回错误(ORA-00054)而不等待锁释放
紧急处理:ALTER SYSTEM KILL SESSION ‘sid,serial#’;
ALTER SYSTEM KILL SESSION命令用于终止Oracle数据库中的指定会话,其完整语法格式为:
ALTER SYSTEM KILL SESSION ‘sid,serial#’ [IMMEDIATE];
参数说明:
sid:会话标识符,可通过查询V$SESSION视图获取。
serial#:会话序列号,用于唯一标识会话实例。
IMMEDIATE:可选参数,指定后会话将立即终止而不等待事务完成。
- log file sync(日志同步)
优化:
组提交(COMMIT_WRITE参数)
异步提交:COMMIT WRITE BATCH NOWAIT;
优化日志写入:使用高速磁盘/调整日志文件大小
- latch: shared pool(共享池闩锁)
触发原因:硬解析过多
排查:
SELECT * FROM v$sqlarea WHERE parse_calls > 1000; -- 高解析SQL
解决:
绑定变量:ALTER SYSTEM SET cursor_sharing=‘FORCE’;(谨慎使用)
刷新共享池:ALTER SYSTEM FLUSH SHARED_POOL;(应急)
3.4 从等待事件到解决方案
案例:订单提交卡顿
现象:
- 用户反馈提交订单时响应慢
- 监控发现log file sync等待激增
诊断步骤:
- 定位相关会话:
SELECT sid, program, sql_id
FROM v$session
WHERE event = 'log file sync';
- 分析SQL:
SELECT sql_text FROM v$sql WHERE sql_id = 'g8ruhm9sxz3tk';
-- 发现为INSERT订单明细
- 检查事务模式:
-- 应用代码检查:每次插入明细后立即提交
- 优化方案:
批量提交:每100条明细提交一次。
使用异步提交:COMMIT WRITE BATCH NOWAIT;
四、AWR报告解读
4.1 核心概念和作用
核心概念:
AWR(Automatic Workload Repository):Oracle内置的性能仓库,每60分钟自动采集一次系统快照(包括SQL执行统计、等待事件、资源消耗等),默认保留8天。
AWR报告:基于两个快照生成的性能分析报告,提供负载概况、等待事件、SQL性能、资源瓶颈等全景视图。
作用:
定位性能瓶颈:识别CPU、I/O、内存或SQL层面的问题根源。
建立性能基线:通过历史快照对比,量化优化效果。
减少人工诊断时间:自动化采集数据,避免手工抓取性能指标。
核心模块解读(附关键指标):
下表为AWR报告中需重点关注的模块及指标:
模块 | 关键指标 | 健康阈值 | 异常影响 |
---|---|---|---|
负载概况(Load Profile) | Redo size/s, Logical reads/s, Hard parses/s | <100次/秒 | 高硬解析导致CPU争用 |
实例效率(Instance Efficiency) | Buffer Hit %, Library Hit %, Soft Parse % | >95% | 低命中率引发I/O暴增 |
Top 10等待事件 | DB CPU,db file sequential read,log file sync | DB CPU排名前 | 高I/O等待暴露存储性能不足 |
SQL统计(SQL Statistics) | SQL ordered by Elapsed Time SQL ordered by Gets | 无固定阈值 | 单条SQL拖垮整个实例 |
深度解析要点:
- 等待事件分析
若log file sync等待过高 → 事务提交频繁,需优化提交方式(如批量提交)。
db file scattered read(多块读)持续高位 → 全表扫描泛滥,检查缺失索引。
- SQL性能分析
关注Elapsed Time排名前5的SQL:
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_AWR('sql_id')); -- 提取执行计划:cite[7]
高Gets(逻辑读)SQL:可能缺少索引或存在低效连接。
4.2 ADDM建议模块
ADDM(Automatic Database Diagnostic Monitor):基于AWR快照的智能诊断引擎,自动分析性能问题并给出优化建议。
核心功能:检测CPU瓶颈、锁争用、I/O问题、SQL负载等,并推荐硬件调整、参数优化、SQL重构等方案。
重要作用:
主动预防:在问题影响业务前提前预警(如预测undo表空间不足)。
跨维度关联:将等待事件、SQL性能、资源配置关联分析。
怎么用?
步骤1:生成ADDM报告
@?/rdbms/admin/addmrpt.sql -- 输入起止快照ID:cite[5]:cite[9]
步骤2:解读建议优先级
ADDM报告按影响程度排序建议,优先处理高收益(Benefit) 且低成本(Cost) 项,例如:
- ✅ 高优先级:通过索引减少全表扫描(预估节省30% DB Time)
- ⚠️ 低优先级:升级CPU(需硬件投资,节省15% DB Time)
步骤3:执行优化动作
- SQL优化示例:
-- 使用SQL Tuning Advisor
DECLAREtask_name VARCHAR2(30);
BEGINtask_name := DBMS_SQLTUNE.CREATE_TUNING_TASK(sql_id => 'abc123');DBMS_SQLTUNE.EXECUTE_TUNING_TASK(task_name);DBMS_OUTPUT.PUT_LINE(DBMS_SQLTUNE.REPORT_TUNING_TASK(task_name));
END;
输出建议可能包括:创建索引、重构SQL、接受统计信息。
- 参数调整示例:
若建议增大PGA_AGGREGATE_TARGET:
ALTER SYSTEM SET pga_aggregate_target=8G SCOPE=SPFILE;
步骤4:验证优化效果
比较优化前后的AWR报告关键指标:
- Elapsed Time下降幅度
- 等待事件减少比例(如db file sequential read降低50%)
4.3 5步定位性能瓶颈
- 选择有效快照范围
问题时段优先(如10:00–11:00 AM),避免包含空闲时间:
SELECT snap_id, begin_time FROM dba_hist_snapshot
WHERE begin_time > SYSDATE - 1/24; -- 最近1小时快照
- 分析负载趋势:检查DB Time vs Elapsed Time
- 若DB Time ≫ Elapsed Time → 系统过载。
- 若DB Time << Elapsed Time → 系统空闲或存在外部阻塞。
- Top等待事件诊断
- DB CPU排名第一 → CPU瓶颈(需检查Top SQL by CPU)。
- enq: TX - row lock contention → 应用事务逻辑缺陷(如未提交事务)。
- SQL性能聚焦:联合分析以下两类SQL
- SQL ordered by Elapsed Time:优化长耗时SQL。
- SQL ordered by Executions:高频SQL即使单次快,总量也可能消耗大资源。
- 内存与I/O瓶颈
- Buffer Hit % < 90% → 需扩大DB_CACHE_SIZE。
- Avg Physical Read Time > 20ms → 存储性能不足(升级SSD或调整HBA队列)。
结语
性能优化是持续过程:
- 监控:通过AWR/v$session_wait捕获问题
- 分析:解读执行计划定位瓶颈
- 解决:索引优化、SQL重构、参数调整
- 验证:对比优化前后性能指标
行动指南: 每周生成AWR报告,每日检查关键等待事件,对TOP SQL持续优化!