Oracle cursor_sharing 优化做完之后,Parse 到底降了多少,不能只看感觉。把 Codex 的 Base URL 改到 TaoToken 后,我让 Codex 根据原文里的 alter system set cursor_sharing='SIMILAR' 参数调整,生成一组监控 Parse 的 SQL,然后在调整前后各跑一次做对比。TaoToken 在这里只提供模型通道,读者拿到 Key 后配通 Codex,就能对 cursor_sharing 改动后的 Parse 变化做复核。这个流程特别适合手里有 Oracle 测试库、又想让 Codex 帮忙写监控脚本的 DBA 或后端同学:你不需要把整段 AWR 报告贴给它,只要把统计视图、采样窗口、负载方式说清楚,它就能给出能落地的 SQL。
1. Oracle cursor_sharing 与 Parse 复测场景
硬解析高的时候,Oracle 会反复做语法分析、语义分析、生成执行计划,CPU 和 latch 都会受影响。cursor_sharing 的作用是让 Oracle 在遇到字面量 SQL 时,尝试把字面量替换成绑定变量,从而让更多 SQL 共享同一个游标。原文里执行的是:
alter system set cursor_sharing='SIMILAR';SIMILAR 这个值在老版本里经常被拿来降低硬解析,但它并不是“改完就一定好”。原因很简单:共享游标之后,执行计划可能变得不稳定,解析次数下降不代表整体响应时间一定下降。所以调优动作做完,必须用监控查询把 Parse 变化量测出来。
1.1 硬解析、软解析和 Parse 统计口径
Oracle 的v$sysstat里有几个关键指标:
| 指标名 | 含义 |
|---|---|
| parse count (total) | 总解析次数,包含硬解析和软解析 |
| parse count (hard) | 硬解析次数,需要生成执行计划 |
| parse count (failures) | 解析失败次数,常见于权限、对象不存在等 |
| execute count | 执行次数,用来判断负载是否真的跑过 |
| session cursor cache hits | 会话游标缓存命中,辅助判断软解析情况 |
硬解析率可以用parse count (hard) / parse count (total)估算。调整 cursor_sharing 前后,重点看 hard parse 是否下降、total parse 是否下降、execute count 是否保持接近。如果 execute count 没变,hard parse 明显下降,说明这次调整至少在这个测试负载下有效。
1.2 为什么要在调整前后各跑一次
实例级统计是累计值,不会自动帮你分段。你只看一次v$sysstat,不知道哪些解析是调整前产生的,哪些是调整后产生的。正确做法是:
- 采集调整前基线;
- 跑一段固定负载;
- 修改
cursor_sharing; - 跑同一段负载;
- 再采集一次统计;
- 计算差值。
这个流程看起来简单,但如果没有 Codex 帮忙生成脚本,手写容易漏指标、漏权限、漏恢复参数。接下来就讲怎么把 Codex 的 Base URL 改到 TaoToken,然后让 Codex 生成这套监控 SQL。
2. TaoToken 前置:创建 Key 与 Codex Base URL
TaoToken 在这里的角色是模型通道,不替代 Oracle,也不替你做 SQL 调优。你需要先拿到 API Key,再把 Codex 的请求地址指到 TaoToken。打开官网创建 Key:
https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=
登录后进入 API Keys 页面创建 Key,链接是:
https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api_keys&utm_campaign=rewrite
创建后把 Key 复制出来,先放在环境变量里,不要写进公开代码仓库。Codex 的 Base URL 填:
https://taotoken.net/api注意这里不要带/v1。有些客户端会自己在后面补/v1,你如果写成https://taotoken.net/api/v1,部分版本会拼成/api/v1/v1,然后报 404。接入细节可以对照文档:
https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite
这部分不需要折腾复杂配置,核心就是两件事:Key 正确,Base URL 不带/v1。配通之后,Codex 就能根据你的 Oracle 场景生成监控脚本。
3. 可复制配置:让 Codex 生成 parse_snap 监控 SQL
先配环境变量。不同版本的 Codex CLI 读取字段可能略有差异,但 OpenAI 兼容方式通常认这两个变量:
export OPENAI_API_KEY="sk-你的TaoTokenKey" export OPENAI_BASE_URL="https://taotoken.net/api" # 确认 Codex 可用 codex --version如果你用的是配置文件方式,可以参考下面结构,但字段名以你本机 Codex 版本为准:
{ "model": "gpt-4.1-mini", "baseURL": "https://taotoken.net/api", "apiKey": "sk-你的TaoTokenKey" }配置完成后,给 Codex 一段明确的 Oracle 复测提示词。提示词越具体,生成的 SQL 越能直接跑。
3.1 给 Codex 的 Oracle 复测提示词
你是 Oracle 性能优化助手。场景:Oracle 19c 测试库,准备把 cursor_sharing 从 EXACT 调整为 SIMILAR。请生成一套可直接执行的 SQL 脚本,要求: 1. 调整前采集 v$sysstat 中 parse count (total)、parse count (hard)、parse count (failures)、execute count 的基线; 2. 生成一段可控的字面量 SQL 负载,重复 500 次,每次 WHERE 条件不同; 3. 调整 cursor_sharing 后再次采集同样指标; 4. 用 SQL 计算调整前后的差值和硬解析率; 5. 同时查询 v$sql,定位测试相关的 sql_id、parse_calls、loads; 6. 给出所需权限和恢复原参数的 SQL。 请输出完整脚本,并标注执行顺序。3.2 Codex 生成的 parse_snap 脚本
下面这套脚本可以直接复制到测试库执行。先建快照表:
CREATE TABLE parse_snap ( phase VARCHAR2(10), name VARCHAR2(64), value NUMBER, snap_ts TIMESTAMP );采集调整前基线:
INSERT INTO parse_snap SELECT 'BEFORE', name, value, SYSTIMESTAMP FROM v$sysstat WHERE name IN ( 'parse count (total)', 'parse count (hard)', 'parse count (failures)', 'execute count' ); COMMIT;跑一段字面量负载。下面这段会让每次 SQL 文本都不同,在 EXACT 下容易触发硬解析:
BEGIN FOR i IN 1..500 LOOP EXECUTE IMMEDIATE 'SELECT /* cs_test */ COUNT(*) FROM dual WHERE 1 = ' || i; END LOOP; END; /查看当前 cursor_sharing 原值,并改成 SIMILAR:
SHOW PARAMETER cursor_sharing; ALTER SYSTEM SET cursor_sharing='SIMILAR' SCOPE=MEMORY;再跑同一段负载:
BEGIN FOR i IN 1..500 LOOP EXECUTE IMMEDIATE 'SELECT /* cs_test */ COUNT(*) FROM dual WHERE 1 = ' || i; END LOOP; END; /采集调整后快照:
INSERT INTO parse_snap SELECT 'AFTER', name, value, SYSTIMESTAMP FROM v$sysstat WHERE name IN ( 'parse count (total)', 'parse count (hard)', 'parse count (failures)', 'execute count' ); COMMIT;计算前后差值:
SELECT a.name, a.value AS before_value, b.value AS after_value, b.value - a.value AS delta, ROUND((b.value - a.value) / NULLIF(a.value, 0) * 100, 2) AS pct_change FROM parse_snap a JOIN parse_snap b ON a.name = b.name WHERE a.phase = 'BEFORE' AND b.phase = 'AFTER' ORDER BY a.name;计算硬解析率:
SELECT phase, MAX(CASE WHEN name = 'parse count (hard)' THEN value END) AS hard_parse, MAX(CASE WHEN name = 'parse count (total)' THEN value END) AS total_parse, ROUND( MAX(CASE WHEN name = 'parse count (hard)' THEN value END) / NULLIF(MAX(CASE WHEN name = 'parse count (total)' THEN value END), 0) * 100, 2 ) AS hard_parse_pct FROM parse_snap GROUP BY phase;再查v$sql,确认测试 SQL 是否被共享:
SELECT sql_id, SUBSTR(sql_text, 1, 80) AS sql_text, parse_calls, loads, executions FROM v$sql WHERE sql_text LIKE '%cs_test%' ORDER BY last_active_time DESC FETCH FIRST 20 ROWS ONLY;如果当前用户没有权限,需要 DBA 授权:
GRANT SELECT ON V_$SYSSTAT TO your_user; GRANT SELECT ON V_$STATNAME TO your_user; GRANT SELECT ON V_$SQL TO your_user; GRANT SELECT ON V_$SQLAREA TO your_user;这套脚本的重点不是“跑完就完”,而是把调整前、调整后的指标放进同一张parse_snap表,后面复核时可以直接 SQL 对比。测试完成后记得恢复原参数:
ALTER SYSTEM SET cursor_sharing='EXACT' SCOPE=MEMORY; -- 如果原值不是 EXACT,按 SHOW PARAMETER 记录的原值恢复4. 验证请求与成功结果:调整前后 Parse 对比
Codex 配置好后,先验证 TaoToken 通道是否通。Base URL 是https://taotoken.net/api,客户端通常会自动补/v1,所以 curl 验证时可以用完整路径:
curl -s https://taotoken.net/api/v1/models \ -H "Authorization: Bearer ${OPENAI_API_KEY}" | head -c 500如果能返回模型列表或类似 JSON,说明 Key 和通道正常。接着在 Oracle 测试库按顺序执行前面的脚本。
4.1 调整前基线结果示例
parse_snap里 BEFORE 阶段可能长这样:
| name | value |
|---|---|
| parse count (total) | 62140 |
| parse count (hard) | 8320 |
| parse count (failures) | 2 |
| execute count | 195430 |
跑完 500 次字面量负载后,再改cursor_sharing='SIMILAR',再跑同样负载。AFTER 阶段示例:
| name | value |
|---|---|
| parse count (total) | 62610 |
| parse count (hard) | 8361 |
| parse count (failures) | 2 |
| execute count | 195930 |
注意这里是实例级累计值,所以要看差值,不是看绝对值。差值如下:
| 指标 | BEFORE 到 AFTER 增量 |
|---|---|
| parse count (total) | 470 |
| parse count (hard) | 41 |
| parse count (failures) | 0 |
| execute count | 500 |
硬解析率从调整前的约 82% 降到约 8.7%,说明在这个测试负载下,字面量 SQL 被更多共享,硬解析明显减少。如果你看到 hard parse 没有下降,先别急着下结论,可能负载文本、共享池状态、其他会话干扰都会影响结果,继续按下一节的排查顺序看。
4.2 成功结果要同时满足什么
一次可信的复测,至少满足这几个条件:
execute count增量接近你实际跑的次数,说明负载真的执行了;parse count (hard)增量相比调整前明显下降;parse count (failures)没有异常升高;v$sql里测试 SQL 的sql_id数量减少,parse_calls与loads比例更合理;- 调整后业务 SQL 的执行计划没有出现明显劣化。
如果第 1 条不满足,说明负载没跑够,或者被其他会话干扰。如果第 2 条不满足,先检查cursor_sharing是否真的生效:
SHOW PARAMETER cursor_sharing;如果显示还是 EXACT,说明修改没生效,或者你在另一个实例上查。RAC 环境下要确认当前会话连接的实例。
5. 本篇常见错排查:401、404 与 parse count 查不到
5.1 Codex 报 401 或 403
通常是 Key 没带对。检查环境变量是否真的导出:
echo $OPENAI_API_KEY echo $OPENAI_BASE_URLKey 复制时不要带前后空格。如果 Key 失效,回到 API Keys 页面重新创建:
https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api_keys&utm_campaign=rewrite
5.2 Codex 报 404
最常见原因是 Base URL 写成了https://taotoken.net/api/v1。Codex 或 SDK 会再补一次/v1,请求路径变成/api/v1/v1/...,自然找不到。按本篇配置,Base URL 只写:
https://taotoken.net/api5.3 SQL 查不到 parse count
v$sysstat的 name 值大小写和空格要完全匹配。建议先用模糊查询确认:
SELECT name, value FROM v$sysstat WHERE name LIKE 'parse count%' ORDER BY name;如果查不到,可能是权限不够,或者你连的是容器/可插拔数据库,需要切到对应容器再查。
5.4 硬解析没有下降
先确认测试 SQL 是否真的产生了大量硬解析。查v$sql:
SELECT sql_id, sql_text, parse_calls, loads, executions FROM v$sql WHERE sql_text LIKE '%cs_test%' ORDER BY last_active_time DESC;如果sql_id还是很多,说明共享效果不明显。还要注意 SIMILAR 在较新版本里已经不是推荐值,生产上更常见的是用绑定变量或cursor_sharing=FORCE,但具体用哪个值必须结合业务 SQL 和测试结果。测试完恢复原参数,避免影响其他实验。
5.5 统计窗口噪声太大
v$sysstat是实例级累计值,测试库如果有其他会话在跑,差值会被污染。尽量在独立测试库、维护窗口或低峰期做。也可以同时用v$mystat看当前会话,但 cursor_sharing 是实例级参数,最终还是要以实例统计为准。
6. 语义一致 CTA:用 TaoToken 固化 Oracle 复测流程
这套流程里,TaoToken 只负责把 Codex 的模型请求接起来。你真正要沉淀的是三样东西:一份可复用的parse_snap脚本、一段固定的字面量负载、一次调整前后的对比查询。下次再改cursor_sharing、共享池参数或 SQL 绑定方式,直接把提示词丢给 Codex,让它按同样结构生成脚本即可。
如果你还在验证模型输出是否适合写 Oracle 监控 SQL,可以先用模型对话做小样本测试:
https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=model_chat&utm_campaign=rewrite
如果你已经准备把 Codex 接进日常排障流程,建议先把 API Key 和接入文档过一遍:
https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api_keys&utm_campaign=rewrite
https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite
如果你长期用 Codex 写 SQL、做 Agent 或批量生成运维脚本,可以看 Coding Plan:
https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite
复测完成后,记得把cursor_sharing改回原值,并保留parse_snap表。下次再做类似优化,直接插入新的 BEFORE/AFTER 快照,就能把 Parse 变化量持续追踪下去。