在排查Oracle数据库性能问题时,最让人头疼的往往不是SQL写得慢,而是不知道它到底慢在哪里。执行计划看起来正常,索引也在用,但一条SQL就是跑了几十秒才返回。这时候Oracle提供的SQL Trace配合TKPROF工具就是最直接有效的诊断手段,它能精确记录SQL语句在数据库内部的每一个动作,包括解析次数、执行时间、逻辑读、物理读、排序方式等关键信息,让你从猜测变成有数据支撑的分析。

什么是SQL Trace,它到底记录了什么
SQL Trace是Oracle内置的跟踪机制,底层通过10046事件实现。当为一个会话开启跟踪后,Oracle会把该会话中所有SQL的执行细节写入一个trace文件,文件存放在由参数user_dump_dest(11g之后逐渐被diagnostic_dest取代)指定的目录下。
根据跟踪信息的详细程度,10046事件分为多个级别,级别越高记录的信息越多,产生的开销也越大:
- 级别1:标准SQL Trace,记录解析、执行、获取以及等待事件的基础信息
- 级别4:在级别1基础上增加绑定变量的值,适合排查绑定变量传入异常的情况
- 级别8:增加等待事件的详细信息,是性能诊断中最常用的级别
- 级别12:同时包含绑定变量值和等待事件详情,信息最全但文件最大
实际排查性能问题时,推荐优先使用级别8,因为它能明确告诉你在执行过程中时间花在了哪些等待事件上,比如db file sequential read说明在等单块读,很可能是索引扫描效率低,而db file scattered read则对应全表扫描的多块读。
如何开启跟踪并定位trace文件
开启SQL Trace主要有几种方式。最经典的是使用DBMS_SYSTEM包设置会话级事件,需要先从v$session中找到目标会话的SID和Serial#:
-- 查找目标会话
SELECT sid, serial#, username, machine
FROM v$session
WHERE username = 'SCOTT';
-- 对指定会话开启级别8的跟踪
EXEC DBMS_SYSTEM.SET_EV(sid => 25, serial# => 1203, \
ev => 10046, level => 8, \
what_might => 'test');
如果是跟踪自己当前所在的会话,可以直接使用DBMS_SESSION包,操作更简单:
ALTER SESSION SET timed_statistics = TRUE; ALTER SESSION SET max_dump_file_size = unlimited; EXEC DBMS_SESSION.SET_SQL_TRACE(TRUE); -- 或者使用dbms_monitor包开启更详细的跟踪 EXEC DBMS_MONITOR.SESSION_TRACE_ENABLE(waits => TRUE, binds => FALSE);
注意在开启跟踪前,务必确认timed_statistics参数为TRUE,否则trace文件中的时间信息会缺失,分析价值大打折扣。同时把max_dump_file_size调大或设为unlimited,避免trace文件写到一半被截断。跟踪完成后要记得及时关闭,否则长事务会话持续写trace会占用大量磁盘空间。
定位trace文件可以查询v$diag_info视图(11g及以上版本),也可以直接到ADR目录下的trace子目录中按会话编号查找,文件名一般是orcl_ora_进程号.trc的格式。
用TKPROF把原始trace变成可读报告
trace文件是纯文本,但内容混杂着大量内部信息,直接阅读效率极低。TKPROF是Oracle自带的命令行格式化工具,位于$ORACLE_HOME/bin目录下,能把这些原始数据汇总成结构化报表:
tkprof /u01/app/oracle/diag/rdbms/orcl/orcl/trace/orcl_ora_23560.trc \
/tmp/report.txt \
explain=system/password \
sys=no \
sort=prsdsk,exedsk,fchdsk
几个关键参数值得说明:explain选项会为每条SQL生成执行计划,方便对照执行细节;sys=no过滤掉SYS用户递归产生的SQL,让报告聚焦在业务SQL上;sort参数决定SQL在报告中按什么排序,按物理读排序能优先看到I/O开销最大的语句,是最常用的排序方式之一。
生成的报告中,每条SQL都分为Parse(解析)、Execute(执行)、Fetch(取数据)三个阶段,每个阶段统计四个维度的数据:count是该阶段调用次数,cpu是消耗的CPU时间,elapsed是总耗时,disk是物理读次数。以一条查询为例,如果看到Parse次数高达几千次,说明应用程序没有使用软解析复用,游标没有被有效共享;如果disk列数值很大而query列(一致性逻辑读)也不小,基本可以判定是全表扫描在拖慢SQL。
解读报表中的关键指标
拿到TKPROF报告后,建议按下面的思路逐项分析:
第一看Parse与Execute的比例。理想情况下一条SQL执行多次只应该解析一次,如果解析次数接近执行次数,说明存在硬解析问题,通常需要检查程序是否使用了绑定变量,或者检查共享池的游标共享设置。过多的硬解析不仅消耗CPU,还会引起latch争用。
第二对比query、current和disk三列。query是一致性读,current是当前模式读,两者相加是总逻辑读;disk是物理读。如果逻辑读很高但物理读不高,说明数据基本都在缓冲区中,SQL慢的原因是访问的数据量本身太大,需要从索引设计或SQL写法入手;如果物理读也很高,则要考虑缓冲区命中率问题或者直接做I/O层面的优化。
第三关注报告末尾的统计汇总部分,尤其是sorts (disk)和sorts (memory)。内存排序速度远快于磁盘排序,如果磁盘排序次数明显,说明PGA中sort_area_size(或自动管理模式下的PGA目标)设置不足,大结果集排序被迫落盘,性能会急剧下降。另外看rows列的返回行数与Fetch次数的关系,Fetch次数约为rows除以数组批量取的行数,如果Fetch次数异常多,说明程序端没有设置好批量取数,网络往返开销白白浪费。
掌握SQL Trace加TKPROF这套组合拳后,大部分慢SQL问题都能快速定位到具体环节。需要注意TRACE本身会带来额外开销,生产环境尽量短时间、小范围开启,拿到足够数据后立即关闭,避免跟踪本身成为新的性能负担。
SQL TraceTKPROFOracle性能优化修改时间:2026-09-13 14:14:32