简介:面向 Oracle 数据库管理员与 SQL 性能调优开发者,这是一套覆盖 Oracle 10g 至 19c 多个版本的调优工具资源包,可帮助定位 SQL 执行效率低、执行计划不稳定等常见问题。压缩包共 205 个文件,以 160 个 SQL 脚本为核心,另有 19 个包体、19 个包规范、5 个说明文档及 2 个网页格式报告,整体仅 927KB,轻量紧凑,便于快速部署和日常使用。当前已有 413 人学习,适合数据库管理员和开发人员在日常维护、故障排查时参考。资源中既包含 SQLT 调优助手工具,也涵盖 SQL 概要文件迁移脚本,支持跨环境传递并应用更优执行计划,从而减少语句响应时间与资源消耗;同时附有包体源码与说明文档,便于理解内部逻辑,可在开发、测试与生产环境之间复用调优策略,有效提升数据库运行的稳定性与整体效率。 手头有条SQL从秒级响应退化到分钟级,应用方连环催,业务方盯得紧,我在终端里翻执行计划、查统计信息、导10053 trace,忙活一个多小时才把诊断材料凑齐。后来同一场景我用SQLT处理,十分钟内拿到一份打包好的HTML报告,问题一目了然。最近整理工具包又翻出 sqlt_10g_11g_12c_18c_19c_5th_June_2020.zip,借这个机会把这套Oracle官方SQL诊断工具的安装、方法选型、实战过程和踩坑经验从头到尾梳理一遍,给同样被慢SQL折磨的DBA和性能工程师做个参考。
文件名看着像补丁包,其实是SQLTXPLAIN(圈内通常叫SQLT)的标准发行包。它的作用很简单:你给它一条SQL,可以是SQL_ID、HASH_VALUE,也可以是SQL全文,它自动收集这条SQL相关的执行计划、对象统计信息、绑定变量、初始化参数、等待事件、优化器trace等十几类诊断数据,最后打包成一个zip,里面是结构化的HTML报告。你把这个zip发给Oracle Support,或者自己打开报告分析,都能高效还原这条SQL在数据库里的完整运行情况。
包名里每个字段都有讲究:sqlt是工具名,10g_11g_12c_18c_19c代表支持的数据库版本区间,5th_June_2020是构建日期。所以只需保留这一个压缩包,就能覆盖从10.2.0.4到19c的大多数主流版本,不用为每个大版本单独找工具,这在维护多套不同版本数据库的环境里非常省心。
这篇文章按“是什么、怎么装、方法怎么选、实战怎么做、报告怎么看、坑怎么避”的顺序展开,适合三类人:被慢SQL追着跑的一线DBA,做性能优化的数据库顾问,以及对Oracle优化器工作机制感兴趣的开发人员。
1. SQLT到底是什么,和AWR、ASH、SQL Monitor有什么区别
先说定位。SQLT做的是SQL级的“全景体检”。Oracle自带工具里,AWR看的是系统层面的历史性能快照,ASH看的是某个时间窗口内活跃会话在干什么,SQL Monitor看的是某条SQL执行期间的实时和历史性能。SQLT则完全不同:它聚焦“一条SQL”,把这条SQL在优化器眼中的一切重要信息都捞出来,回答三个问题:它为什么慢?CBO看到的统计信息到底是什么样子?换执行计划甚至换种写法能不能变快?
SQLT是Oracle Support团队维护的PL/SQL程序集,最早由Carlos Sierra开发,后来并入官方工具序列。它用纯SQL和PL/SQL实现,不装Agent、不重启库、不额外起进程,对生产环境的侵入很小。下载需要MOS账号,官方文档入口是Doc ID 215187.1,工具本身免费。
为什么文件名要覆盖10g到19c这么多版本?因为SQLT大量使用内部视图和DBMS包,而10g的优化器模型和19c之间差异巨大,脚本必须做版本兼容。解压后你会看到utl目录下按版本区分的许多脚本,安装时工具会自动识别当前库版本,选择合适的逻辑执行。这也提醒我一件事:这套脚本虽然兼容面广,但生产库上装SQLT,最好还是在每个目标库里单独装一份,别指望用19c库跑出的SQLT包去诊断10g库的SQL——库版本不同,收集到的部分内部信息不可比。
我自己用SQLT最频繁的场景是这几类:应用升级后SQL执行计划突变;同一套SQL在测试库正常、生产库缓慢;以及需要向Oracle Support提交性能问题时,用SQLT生成的zip作为标准附件。它不负责改写SQL,但能把问题压缩成一份“可交付”的诊断产物。
2. 安装与初始化:十分钟搞定,但有几个前提
SQLT的安装相当轻量,在SQL*Plus里执行两个脚本即可,但前提条件要先满足。
2.1 环境要求
数据库版本必须是10.2.0.4以上,这套包正好覆盖10g到19c。还要有SYSDBA权限的账号,因为安装脚本要建用户、建角色、建视图。磁盘空间要求不高,默认表空间留出50MB到100MB就够。整个过程不需要重启实例,这点对生产环境很友好。
如果数据库是12c以上的多租户架构,要特别注意:SQL在哪个容器里执行,就要在哪个容器里安装SQLT对象。只装在CDB根容器,到PDB里调用会报ORA-00942;反过来只装在PDB,根容器又会缺对象。我习惯的做法是CDB和业务PDB各装一遍,成本很低,省得后面排查权限问题。
2.2 安装步骤
解压后进入目录,用SYS登录执行:
unzip sqlt_10g_11g_12c_18c_19c_5th_June_2020.zip cd sqlt_10g_11g_12c_18c_19c_5th_June_2020 sqlplus / as sysdba在SQL*Plus里依次执行:
SQL> @install/sqlt_create_sys.sql SQL> @install/sqlt_create_user.sql第一个脚本创建SQLT自己用的辅助表,比如plan表和一些统计信息采集视图,这些对象建在SYS schema下。第二个脚本创建专用用户sqltxpl,默认密码也是sqltxpl,并授予sqltxpl_role角色,这个角色囊括了运行诊断SQL所需的各类视图和包的执行权限。
安装完成后,日常使用不建议再用SYS登录,而是用sqltxpl用户操作:
sqlplus sqltxpl/sqltxpl@orclpdb1注意:sqlt_create_user.sql执行时如果提示用户已存在,说明之前装过;此时要决定是drop掉重建,还是复用现有用户补授权。我一般直接drop user sqltxpl cascade重建,避免权限残留导致奇怪问题。
安装后可以跑一下demo目录里的测试脚本确认环境正常,也可以直接开始用。说实话,我见过不少同事卡在安装这一步,大多是因为在CDB和PDB之间搞混了容器,或者用了普通账号执行安装脚本,注意这两点就没什么坑了。
3. 模式与方法选型:XPLORE、XECUTE、XTRXPLORE到底怎么选
用SQLT时的核心入口是sqltxtract.sql,调用语法大致是:
SQL> @sqltxtract.sql <SQL输入> <工作模式> <统计信息处理级别>SQL输入可以是SQL_ID、HASH_VALUE或SQL全文。工作模式决定SQLT要不要真正执行你的SQL,这是最需要想清楚的选择。三种主要模式对比如下:
| 模式 | 是否执行SQL | 收集内容 | 适用场景 |
|---|---|---|---|
| XPLORE | 不执行 | 基于现有统计信息分析优化器,生成多种执行计划与CBO诊断信息 | SQL非常慢、不能随便重复执行的场景 |
| XECUTE | 执行,默认限制返回行数 | 真实执行计划、实际等待事件、会话统计、运行时资源消耗 | 常规首选,能拿到最接近真实情况的信息 |
| XTRXPLORE | 执行并附加trace | 在XECUTE基础上再做10053等优化器trace深挖 | 需要追根溯源,弄清优化器为什么这么选 |
第三个参数是统计信息处理级别,它控制SQLT是否重新收集统计信息,常见取值:
- 0:不碰统计信息,完全使用现有的CBO统计,适合只想看当前状态的情况;
- 1:对SQL涉及的表和索引重新收集统计信息,推荐默认值,能排除“统计信息过期导致选错计划”的干扰;
- 2:在级别1基础上进一步收集直方图等细粒度统计,适合字段分布极度不均、需要看数据倾斜的场景。
举个例子,一条报表SQL跑了半小时都出不来,你肯定不想用XECUTE再让它跑一遍。这时选XPLORE加级别0,SQLT只做静态分析,基于现有统计信息生成CBO眼中的执行计划,既安全又能定位问题。反过来,如果SQL只是从50毫秒退化到5秒,完全可以接受再执行一次,那就用XECUTE获取真实运行时的等待和资源数据,诊断价值比纯静态分析高得多。
选择的核心逻辑就一句话:你愿意承受多大代价,就换取多接近真实的数据。级别越高、模式越激进,数据越全,但对目标SQL的影响也越大。我给客户的建议是:没有把握的SQL先用XPLORE看计划,再决定要不要升级到XECUTE。
4. 实战演示:给一条19c上的慢SQL做一次完整体检
下面用一次实际诊断过程说明完整操作。环境是一套19c单实例,业务反馈某张订单汇总表的查询越来越慢,我在库里查到这条SQL的SQL_ID是b2x7k6j1m0r9z(示例值),执行计划已经从索引扫描变成了大表全扫。
4.1 执行SQLT
用sqltxpl用户登录目标PDB:
sqlplus sqltxpl/sqltxpl@orclpdb1然后执行:
SQL> set long 200000 SQL> set pagesize 0 SQL> set linesize 300 SQL> @sqltxtract.sql b2x7k6j1m0r9z XECUTE 1工具开始后会在终端打印进度,大致经历几个阶段:读取SQL文本和绑定变量、创建内部临时表、收集涉及对象的统计信息、执行SQL并抓取真实执行计划、最后打包生成zip文件。整个过程大概几分钟,取决于SQL复杂度和对象大小。结束后在SQLT的日志目录下会生成一个类似sqlt_s_b2x7k6j1m0r9z_202606051015.zip的压缩包。
4.2 从终端输出能先看出什么
SQLT在终端里会先展示一段SQL本身的信息,包括SQL文本、绑定变量、所在schema。这一步非常重要,我建议先确认抓到的SQL确实是要诊断的那条,尤其是通过SQL_ID匹配时,如果SQL不在共享池里,工具会直接报错提示找不到。绑定变量那边也能看出问题:比如变量值传入后,优化器估算的选择性明显偏离实际返回行数,这类基础信息在终端就能快速获取,不用等报告生成。
4.3 打开HTML报告找根因
打开zip里的主HTML,我先看“CBO Execution Plan”板块。这份报告中的计划对比很清楚:
| 计划来源 | 访问路径 | 估算行数 | 实际行数 | Cost |
|---|---|---|---|---|
| 当前执行计划 | ORDER_DETAILS全表扫描 | 12,400,000 | 11,800,000 | 18,432 |
| 替代计划A | ORDER_DETAILS索引SK_ORDER_DT范围扫描 | 86,000 | 78,500 | 2,841 |
| 替代计划B | 索引SK_ORDER_DT+回表+排序 | 86,000 | 78,500 | 3,102 |
差异非常明显:CBO估算全表扫描12,400,000行,实际返回11,800,000行,说明扫描路径本身没问题,问题在于统计信息或者执行路径选择逻辑。再切到“Object Statistics”板块,发现ORDER_DETAILS表的LAST_ANALYZED是一年多以前,且PURGE_FLAG=‘Y’的数据占全表42%,旧统计完全没反映这批数据。根因基本锁定:统计信息过期加上大量已标记删除的数据,导致优化器认为全扫更便宜。
处理措施就很直接了:先按业务规则清掉或归档PURGE_FLAG=‘Y’的历史数据,再对ORDER_DETAILS及相关索引重新收集统计信息,最后让SQL重新解析。这套操作做完,SQL回到秒级。SQLT在这里的真正价值,不是替我做决定,而是把“计划差异、统计信息过期、数据分布异常”这三条线索一次性摆到桌面上,省去了逐项手工排查的时间。
4.4 生产库不能随便跑SQL怎么办
有的场景下,生产SQL涉及超大表,或者本身就是UPDATE/DELETE,直接XECUTE风险太高。我一般用两个替代方案:一是改用XPLORE模式,让SQLT只做静态分析,不真正执行;二是SQLT支持“异地诊断”思路,把目标schema用Data Pump导出到一套测试库,在测试库上安装SQLT后再跑XECUTE。虽然导入导出有些额外工作量,但对核心生产环境而言,这个隔离是值得的。
5. 报告拿到手,优先看哪六个板块
SQLT生成的HTML报告信息量很大,第一次看容易迷失在大量表格里。我按自己的使用频率排个序,新手按这个顺序看基本不会跑偏。
5.1 SQL Text与绑定变量
先确认诊断对象。报告开头会展示SQL全文和绑定变量快照,同时标注SQL所在schema、执行频率、平均执行时间等元信息。绑定变量的实际值要重点看——很多执行计划问题都源于变量值导致的选择性误判。这份报告里会把每个绑定变量的值、数据类型、是否在SQL中被隐式转换标出来,能少走很多弯路。
5.2 CBO Execution Plan
这是核心板块。SQLT会展示多套执行计划:当前正在使用的计划、基于现有统计信息重新生成的计划、以及加上不同hint后的替代计划。每套计划的Cost、基数估算、物理读写、访问路径都列在表格里。我通常会先定位Cost最高的那步操作,再看它对应的对象是否有索引可用、统计信息是否新鲜。这个板块基本替代了手工执行EXPLAIN PLAN再加各种hint试错的流程。
5.3 Differential Report
这是SQLT最让我惊喜的功能,没有之一。它能把两套执行计划并排对比,差异项用颜色标出:基数估算变了多少、访问路径换了哪个、哪个hint导致了变化,一目了然。比如你怀疑是某个参数改动导致计划翻转,SQLT可以直接生成改动前后的计划差异报告,省去自己拿两个spool文件逐行核对的时间。
5.4 Optimizer Environment
这个板块列出SQL执行时优化器相关的初始化参数,包括optimizer_features_enable、optimizer_mode、各种adaptive参数等。很多计划问题是参数层面的,比如某套库被人改了optimizer_features_enable,SQLT会在报告里直接标注出“当前参数与默认值的差异”,这比你在库里逐个show parameter高效得多。
5.5 Object Statistics
统计信息是执行计划的地基。SQLT会列出SQL涉及的所有表和索引的统计信息,包括行数、块数、直方图、最后分析时间,并和实际值做对比。如果发现某张表的统计信息显示1万行,实际查询返回100万行,这就是明显的统计信息失真。报告里还会标注哪些对象完全没有统计信息——在19c上动态采样有时能兜底,但复杂SQL一旦基数估算错,计划就容易翻车。
5.6 Waits与SQL Monitor
XECUTE模式下,SQLT会抓取SQL执行期间的真实等待事件,比如db file sequential read、direct path read、enq: TX等,并统计等待次数和总耗时。配合SQL Monitor板块(12c以上可用),能还原SQL执行的时间线,看出瓶颈到底在I/O、CPU还是锁等待。我遇到过很多案例,SQL本身不慢,慢在等一个被锁的行,这种问题只看执行计划是发现不了的,必须看等待事件。
报告里其实还有10053 trace、10046 trace等原始材料,属于进阶内容。想研究优化器为什么选A计划而不选B计划时,打开10053 trace看cost计算过程,收获很大,但不适合新手入门。
6. 常见问题与避坑实录
SQLT用熟练之后很顺手,但初期有几个坑我基本每次培训都会遇到,整理成速查表:
| 现象 | 可能原因 | 处理办法 |
|---|---|---|
| 报ORA-20000: SQLT找不到SQL_ID | SQL_ID不在共享池,或SQL已被淘汰 | 改用SQL全文输入,或先让SQL跑一次再诊断 |
| 安装时报ORA-00942 | 用非SYS用户执行了安装脚本 | 用SYSDBA身份重新执行install脚本 |
| 输出了报告但没生成zip | 日志目录无UTL_FILE写权限 | 检查并创建SQLT要求的目录对象,赋读写权限 |
| XECUTE执行时间过长 | SQL本身代价极高,返回行数虽限制但排序/全扫仍耗时 | 改用XPLORE模式,或配合MAXROWS参数进一步限制 |
| 12c/19c多PDB下报对象不存在 | 目标PDB里没有安装SQLT对象 | 在对应PDB里重跑sqlt_create_sys.sql和sqlt_create_user.sql |
| 报告中的SQL文本含敏感业务数据 | 这是正常现象,SQL全文会被记录 | 外发Oracle Support前手动检查,必要时脱敏处理 |
几个实战经验再单独说说。
第一,不要把SQLT当成“自动优化器”。它不生成改写建议,也不自动改SQL,它做的是高质量的信息收集和呈现。最终判断还是靠人。但也正因为这样,它非常客观,不会像某些优化工具那样给出拍脑袋的建议。
第二,用SQL全文做输入时,匹配是精确的,空格、换行、大小写都会影响匹配结果。我通常优先用SQL_ID,只有在共享池里找不到时才用全文,并且会从AWR或历史会话里复制完整文本,避免手输漏字符。
第三,在RAC环境下,一个SQL_ID可能对应多个实例上的不同版本,SQLT默认诊断当前连接的实例。如果需要分析其他实例上的SQL,要么连接到对应实例执行,要么在参数里指定instance_id,别在一个节点上诊断另一个节点的问题,容易拿到不完整的数据。
第四,SQLT运行前最好确认默认表空间余量。它要创建一些临时表来模拟SQL对象,如果表空间撑满,诊断过程会报错,前功尽弃。我在大表环境下习惯先看dba_data_files确认余量,再看diagnostic_dest的磁盘空间,因为最终zip也要写在那里。
最后,聊一点我的个人体会。刚开始用SQLT时,我也觉得它的报告太厚、信息太杂,一度还是习惯手工查视图。但用多了之后,我反而把SQLT当成一个“学习优化器的教具”:每次拿到一份计划异常的XECUTE报告,我都会顺着它的Differential提示打开10053 trace,看看CBO到底因为哪一项统计信息差异改变了cost判断。这样积累下来的经验,比单纯背调优技巧要扎实得多。也正因为如此,我这个10g用到19c的老包一直没删,每次版本更新也只是在这个命名基础上替换新日期而已。如果你还没用过SQLT,建议下次遇到慢SQL时,别急着加班手动翻数据字典,先把它跑一遍,很多问题自己就浮出来了。
本文还有配套的精品资源,点击获取