1. 为什么 DBA_HIST_ACTIVE_SESS_HISTORY 一查就慢
DBA_HIST_ACTIVE_SESS_HISTORY是 Oracle AWR 里做历史会话分析绕不开的一张视图,它记录的是每个采样点上的活动会话快照,能回答“凌晨三点到底谁在拖库”“某个 SQL_ID 在哪个时间段集中爆发”这类问题。但很多 DBA 第一次上手就卡住:明明只查两个小时的窗口,SQL 跑了几分钟还没出结果,甚至把临时表空间撑爆。核心原因有三个。
第一,这张视图底层是WRH$_ACTIVE_SESSION_HISTORY,数据量跟采样频率、实例数、并发会话数成正比。一个跑了半年的库,几千万行是常态,全表扫一遍自然慢。第二,很多人习惯SELECT *,而这张表字段多、宽,还带 LOB 相关的 SQL_TEXT 关联,回表代价高。第三,过滤条件写法不对,SAMPLE_TIME用函数包住或者格式不匹配,导致分区裁剪失效,Oracle 只能老老实实扫所有 AWR 分区。
我见过最典型的慢查询长这样:
SELECT t1.*, dbms_lob.substr(sqltext.SQL_TEXT,1000,1) FROM DBA_HIST_ACTIVE_SESS_HISTORY t1 LEFT OUTER JOIN DBA_HIST_SQLTEXT sqltext ON t1.SQL_ID = sqltext.SQL_ID WHERE t1.SAMPLE_TIME BETWEEN TO_DATE('2018-02-03 03:00:00','YYYY-MM-DD HH24:MI:SS') AND TO_DATE('2018-02-03 05:30:00','YYYY-MM-DD HH24:MI:SS') ORDER BY t1.SAMPLE_TIME DESC;问题出在SELECT t1.*把几十个字段全拉出来,ORDER BY SAMPLE_TIME DESC又强制排序,加上DBA_HIST_SQLTEXT的 LOB 字段,执行计划里大概率出现TABLE ACCESS FULL加SORT ORDER BY,两个都是吃资源的动作。调优思路其实很清晰:只取需要的列、让分区裁剪生效、把排序和 LOB 处理往后放。这篇就按这个思路,把改写后的 SQL 一步步跑通,再通过统一 Key/API 通道接入 TaoToken 做验证,把执行计划和耗时对比摆出来。
适合谁看:日常要做 AWR 历史会话分析、被这张视图拖慢过、想找一套可复制改写模板的 Oracle DBA。下面所有 SQL 都能直接贴进 SQL*Plus 或 SQL Developer 跑。
2. 接入 TaoToken 前的准备:统一 Key 与 API 通道
调优 SQL 这件事,光在本地库上跑还不够,很多时候需要把改写前后的执行计划、耗时数据、甚至 SQL 文本丢给模型做对比分析,或者让模型帮忙看执行计划里的异常算子。这时候如果每个工具都单独配一套 Key,管理起来很乱。TaoToken 的思路是提供一个统一的 API 通道,把模型调用收敛到一个 Base URL 和一把 Key 上,本地脚本、IDE 插件、命令行工具都走同一个入口。
先说清楚它是什么:TaoToken 是一个模型 API 聚合服务,你拿到一把 Key 之后,通过统一的 Base URL 就能调用不同模型,适合做 SQL 调优验证、执行计划解读、脚本生成这类需要反复试的活。官网入口在 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 地址是 https://taotoken.net/api ,注意 API 地址不带 UTM 参数,配置的时候别把跟踪参数拼进去。
拿 Key 的路径很直接:进控制台,在 API Keys 页面创建一把新 Key。控制台地址是 https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API Keys 管理页在 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。创建完记得复制保存,页面刷新后就不再完整显示了。
这里要强调一个配置三件套的概念,不管你用哪种客户端,接入任何模型服务都离不开这三个东西:Base URL、API Key、Model ID。Base URL 填https://taotoken.net/api,API Key 填你刚创建的那串,Model ID 按你要用的模型填。这三件套缺一个都连不上,后面排障章节会专门讲配错的表现。
如果你只是想先验证模型能不能通,可以用模型对话页面直接试:https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。如果是长期做编码和 Agent 类的活,比如让模型持续帮你分析 AWR 报告,那更适合用 Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,配置细节以文档为准。
准备工作就这些,不需要装额外客户端,一把 Key 加一个 Base URL 就能开始。下面进入正题,先改写 SQL。
3. 可复制的 AWR 采样查询改写与配置片段
改写目标很明确:减少返回列、保证分区裁剪、避免不必要的排序和 LOB 处理。先看改写后的 SQL,我把它拆成两步,第一步只取关键字段做筛选,第二步再按需关联 SQL 文本。
-- 第一步:只取关键列,让 SAMPLE_TIME 分区裁剪生效 SELECT t1.SAMPLE_TIME, t1.SQL_ID, t1.SQL_PLAN_HASH_VALUE, t1.SESSION_ID, t1.SESSION_SERIAL#, t1.EVENT, t1.WAIT_CLASS, t1.BLOCKING_SESSION, t1.MACHINE, t1.PROGRAM FROM DBA_HIST_ACTIVE_SESS_HISTORY t1 WHERE t1.SAMPLE_TIME >= TO_DATE('2018-02-03 03:00:00','YYYY-MM-DD HH24:MI:SS') AND t1.SAMPLE_TIME < TO_DATE('2018-02-03 05:30:00','YYYY-MM-DD HH24:MI:SS') ORDER BY t1.SAMPLE_TIME DESC;关键改动:把BETWEEN换成>=和<,边界更清晰,分区裁剪更稳;去掉SELECT *,只留分析真正要用的列;ORDER BY保留但作用在窄结果集上,代价小很多。
第二步,如果确实需要 SQL 文本,单独关联,并且用DBMS_LOB.SUBSTR限制长度,别整段拉:
SELECT t1.SAMPLE_TIME, t1.SQL_ID, t1.SQL_PLAN_HASH_VALUE, DBMS_LOB.SUBSTR(s.SQL_TEXT, 500, 1) AS SQL_TEXT_500 FROM DBA_HIST_ACTIVE_SESS_HISTORY t1 LEFT OUTER JOIN DBA_HIST_SQLTEXT s ON t1.SQL_ID = s.SQL_ID WHERE t1.SAMPLE_TIME >= TO_DATE('2018-02-03 03:00:00','YYYY-MM-DD HH24:MI:SS') AND t1.SAMPLE_TIME < TO_DATE('2018-02-03 05:30:00','YYYY-MM-DD HH24:MI:SS') AND t1.SQL_ID IS NOT NULL ORDER BY t1.SAMPLE_TIME DESC;注意AND t1.SQL_ID IS NOT NULL,把没有 SQL_ID 的会话(比如空闲等待)过滤掉,减少关联行数。
接下来是接入 TaoToken 的配置片段。如果你用命令行工具或者脚本调用,配置通常写在一个 JSON 或 TOML 文件里。以常见的 OpenAI 兼容格式为例,配置文件长这样:
{ "base_url": "https://taotoken.net/api", "api_key": "sk-你的Key", "model": "你的Model ID", "timeout": 60 }如果你用的是支持 TOML 的客户端,等价写法:
[provider] base_url = "https://taotoken.net/api" api_key = "sk-你的Key" model = "你的Model ID"再给一个 Claude Code 场景下的 settings 片段,路径按你本地实际配置走:
{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_API_KEY": "sk-你的Key", "ANTHROPIC_MODEL": "你的Model ID" } }三件套再强调一遍:Base URL 是https://taotoken.net/api,API Key 是你创建的那串,Model ID 按需填。这三个值在 JSON、TOML、settings 里字段名可能不同,但含义一致。配好之后,你的调优脚本就能把改写前后的 SQL、执行计划、耗时数据发给模型做对比分析。
4. 验证请求与成功结果:执行计划对比与耗时
配置好之后,先做一次最小验证,确认通道是通的。用 curl 发一个最简单的请求:
curl https://taotoken.net/api/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer sk-你的Key" \ -d '{ "model": "你的Model ID", "messages": [{"role": "user", "content": "回复 OK 两个字母即可"}] }'返回里能看到choices数组,第一条 message 的 content 是OK,说明 Key、Base URL、Model ID 三件套都对。如果返回 401,说明 Key 有问题;如果报连接错误,检查 Base URL 是不是写成了带 UTM 的地址。
通道通了之后,回到 SQL 调优本身。在 Oracle 里对比改写前后的执行计划,用EXPLAIN PLAN或者直接看DBMS_XPLAN.DISPLAY_CURSOR。改写前的计划里,你会看到TABLE ACCESS FULL作用在WRH$_ACTIVE_SESSION_HISTORY上,外加SORT ORDER BY。改写后,理想情况下应该出现PARTITION RANGE ITERATOR配合INDEX RANGE SCAN,排序算子消失或者代价大幅下降。
实测下来,两个小时的窗口,改写前跑三到五分钟很常见,改写后通常能压到十几秒以内,具体取决于库的规模和 AWR 保留策略。你可以用下面这个方式记录耗时:
SET TIMING ON -- 贴入改写后的 SQL SET TIMING OFFTIMING ON会在每条语句执行后打印Elapsed,直接对比数字就行。
把执行计划和耗时数据整理成文本,通过 TaoToken 发给模型,让它帮你判断计划里还有没有可优化的算子。比如你可以这样组织 prompt:
下面是 Oracle AWR 查询改写前后的执行计划,请指出改写后是否还有全表扫描或高代价排序算子,并给出进一步建议。 改写前计划:... 改写后计划:...模型返回的分析结果如果提到某个算子代价高,你就回到 SQL 里针对性调整,比如加 hint、改过滤条件、或者把关联拆成临时表。这个循环跑几轮,SQL 基本就稳了。
5. 本篇常见错排查:401、local proxy failed、reading choices、OAuth
配置和验证过程中,报错集中在几个地方,逐个说清楚。
401 Unauthorized:最常见。原因就三个——Key 复制不全、Key 前后有空格、Key 已经失效。检查方法:把 Key 重新复制一遍,注意别把换行符带进去。如果用的是环境变量,确认echo $ANTHROPIC_API_KEY输出的是完整 Key。还有一种情况是 Base URL 写错了,比如写成了https://taotoken.net/api/带尾斜杠,某些客户端会拼出双斜杠导致鉴权失败,去掉尾斜杠即可。
local proxy failed:这个报错通常出现在客户端配置了本地代理,但代理没启动或者端口不对。排查顺序:先确认本地代理进程在跑,再确认客户端里配的代理地址和端口跟实际一致。如果你根本没配代理,检查客户端是不是默认读了系统代理设置。把代理配置清空,直连https://taotoken.net/api再试。
reading choices 相关报错:一般是返回体解析失败。可能原因:请求的 Model ID 不存在,服务端返回了错误结构,客户端却按正常结构去读choices字段。解决办法:先用 curl 手动发一次请求,看返回的 JSON 结构里有没有choices。如果没有,看error字段里的提示,多半是 Model ID 写错了。确认 Model ID 拼写,跟文档里列出的保持一致。
OAuth 相关报错:如果你用的是 Claude Code 这类工具,它可能默认走 OAuth 登录流程,而不是 API Key。报错信息里出现 OAuth 字样时,说明工具在尝试交互式登录。解决办法是在配置里显式指定 API Key 模式,把ANTHROPIC_API_KEY填上,同时确认ANTHROPIC_BASE_URL指向https://taotoken.net/api。如果工具同时支持 OAuth 和 API Key,优先用 API Key,避免登录态过期带来的问题。
再补一个容易忽略的点:Codex 的auth.json配置。如果你用 Codex 类工具,认证信息写在auth.json里,格式大致是:
{ "api_key": "sk-你的Key", "base_url": "https://taotoken.net/api" }改完auth.json记得重启工具,否则读的还是旧配置。三件套(Base URL、Key、Model ID)在任何工具里都要对齐,缺一个或者写错一个,报错表现各不相同,对照上面的清单排查能省不少时间。
6. 把调优验证固化成日常流程
SQL 改写和通道验证跑通一次之后,建议把它固化成日常动作。我的做法是准备两个脚本:一个负责在 Oracle 里跑改写前后的 SQL 并记录执行计划和耗时,输出成文本;另一个负责把文本通过 TaoToken 发给模型,拿回分析建议。两个脚本用同一把 Key、同一个 Base URL,配置只维护一份。
模型对话入口适合临时验证:https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。如果你每天都要做 AWR 分析、执行计划解读这类活,用 Coding Plan 更省事:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。Key 的管理统一在 API Keys 页面:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。接入细节以文档为准:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。
最后留一个实用技巧:AWR 查询的窗口尽量别超过两小时,窗口越大分区扫描越多,再好的改写也救不回来。如果确实要看长周期趋势,先用聚合查询把粒度降下来,比如按小时分组统计等待事件,再针对异常时段做细查。这样既快又准,配合模型分析,历史会话排查的效率能提一大截。