如果你的 AI Agent 能自己查锁、诊断慢 SQL、定位阻塞源头——它差的不是推理能力,而是一张把「人话」翻译成 Oracle 系统视图的对照表。oracle/skills 里这个 13KB 的映射文件(https://github.com/oracle/skills/blob/main/db/agent/nl-to-sql-patterns.md),就是做这件事的。


一、当 AI 面对 Oracle 的上千个系统视图

通用大模型写 SELECT ... FROM orders WHERE ... 没有问题。但当你问:

“谁锁了这张表?”
“昨晚那个失败的定时任务,日志在哪?”
“帮我看看哪些索引从来没用过。”

AI 面临的问题不是「不会写 SQL」,而是 「不知道该查哪张系统视图」

Oracle 有上千个 v$dba_ 视图。v$sessionv$lockv$sqldba_hist_sqlstatdba_scheduler_job_log……每个都有特定的列名、关联方式和权限要求。AI 的训练数据里不缺这些知识,但它缺乏一个结构化的索引——当用户说「锁」,AI 应该立刻知道去 v$session 里找 blocking_session 列做自连接

这就是 nl-to-sql-patterns.md 要解决的问题。

它不是一本 SQL 语法书——窗口函数怎么写、CTE 怎么嵌套、PIVOT 怎么用,那是 sql-patterns.md 的领域。这张表只盯着一件事:把运维人员和 DBA 的自然语言需求,精准翻译成 Oracle 系统视图的正确查询


二、运维诊断:从「数据库慢了」到精准定位

文件中「性能诊断」和「锁与阻塞」两个板块共 10 条映射,是整张表最有价值的部分——它们覆盖了 DBA 日常排障的核心路径。

2.1 等待事件:诊断的起点

-- "What's waiting in the database?"
SELECT event, COUNT(*)
FROM   v$session
WHERE  wait_class != 'Idle'
GROUP  BY event
ORDER  BY 2 DESC;

这条 SQL 看似简单,但映射表给了三个关键过滤条件:

  • wait_class != 'Idle'——排除空闲等待(如「SQL*Net message from client」),否则结果会被大量正常的空闲连接淹没
  • GROUP BY event——按等待事件聚合,一眼看出当前瓶颈集中在哪个环节
  • ORDER BY 2 DESC——频率最高的排最前,紧急程度一目了然

没有这个模式,AI 大概率写出 SELECT event FROM v$session 然后让用户面对几百行输出自己找规律。

2.2 阻塞链路:v$session 自连接的奥秘

最容易被 AI 写错的是锁诊断。阻塞者和被阻塞者的信息都在同一张 v$session 里,通过 blocking_session 列关联:

SELECT blocker.sid AS blocker_sid,
       blocker.username AS blocker_user,
       blocked.sid AS blocked_sid,
       blocked.username AS blocked_user,
       blocked.seconds_in_wait,
       blocked.event,
       obj.object_name
FROM   v$session blocked
JOIN   v$session blocker ON blocked.blocking_session = blocker.sid
LEFT   JOIN v$lock lk ON lk.sid = blocker.sid
                      AND lk.type = 'TM'
                      AND lk.lmode > 0
LEFT   JOIN dba_objects obj ON obj.object_id = lk.id1
WHERE  blocked.blocking_session IS NOT NULL
ORDER  BY blocked.seconds_in_wait DESC;

这里有四个 AI 不可能凭空猜对的点:

关键点 为什么 AI 猜不到
blocking_session v$session 有几十个列,这个列名不直观,没用过的人根本不知道
v$session 自连接 同一张视图 JOIN 自己——不是常规思维路径
v$locktype = 'TM' + lmode > 0 TM 是表级锁(DML),TX 是事务锁。必须同时检查锁类型和锁模式——lmode > 0 确保只取实际持有的锁,滤掉仅处于请求状态的行
dba_objectsobject_id = lk.id1 v$lockid1 存的是 object_id 而非 object_name,需要再 JOIN 一次翻译成可读的对象名

这张表的核心价值不是「告诉 AI v$session 的存在」,而是把四张视图之间的正确关联路径一次性给出。 AI 不需要推理,直接复用。

2.3 慢 SQL 定位:从实时到历史

映射表区分了两个层次——实时查询和 AWR 历史,各自解决不同的问题场景:

实时层面(当前正在跑的慢查询——适合即刻排障):

SELECT s.sid, s.serial#, s.username,
       ROUND(s.last_call_et / 60, 1) AS running_minutes,
       sq.sql_text
FROM   v$session s
JOIN   v$sql sq ON s.sql_id = sq.sql_id
              AND s.sql_child_number = sq.child_number
WHERE  s.status = 'ACTIVE'
  AND  s.last_call_et > 60
  AND  s.username IS NOT NULL
ORDER  BY s.last_call_et DESC;

几个值得注意的过滤细节:s.username IS NOT NULL 排除了 Oracle 后台进程(如 PMON、SMON),避免干扰结果;last_call_et > 60 可调——60 秒只是示范阈值,生产环境中按需调整。

历史层面(过去 24 小时最耗资源的 SQL——适合事后复盘):

SELECT s.sql_id,
       ROUND(s.elapsed_time_delta / 1e6 / s.executions_delta, 2) AS avg_sec,
       s.executions_delta AS executions,
       SUBSTR(t.sql_text, 1, 100) AS sql_preview
FROM   dba_hist_sqlstat s
JOIN   dba_hist_sqltext t USING (sql_id)
WHERE  s.snap_id IN (
  SELECT snap_id FROM dba_hist_snapshot
  WHERE begin_interval_time > SYSDATE - 1
)
  AND  s.executions_delta > 0
ORDER  BY s.elapsed_time_delta DESC
FETCH  FIRST 20 ROWS ONLY;

文件在这个历史查询旁加了明确标注——需要 Diagnostics Pack 许可。这不是技术细节,是合规提醒。AI 如果不知道这个限制,可能在无许可环境里执行 dba_hist_* 查询,轻则报 ORA-00942,重则违反许可协议。

注意 executions_delta > 0 的作用:保护除法运算——elapsed_time_delta / executions_delta 在分母为零时会报错,这个谓词防的就是这种情况。

2.4 定时任务排障

映射表还覆盖了一个容易被忽视的场景——调度任务失败排查:

-- Recent job failures
SELECT job_name, log_date, status, error#, additional_info
FROM   all_scheduler_job_log
WHERE  owner = :schema
  AND  status = 'FAILED'
  AND  log_date > SYSTIMESTAMP - INTERVAL '7' DAY
ORDER  BY log_date DESC;

all_scheduler_job_logall_scheduler_job_run_details 这两张表,很多有经验的 DBA 都不一定随时记得列名,更别说 AI。映射表直接给出了标准查询,连 INTERVAL '7' DAY 这种 Oracle 特有的时间间隔写法都给好了——AI 独自写的时候大概率会用 SYSDATE - 7,虽然结果近似,但 SYSTIMESTAMP - INTERVAL '7' DAYlog_date(TIMESTAMP 类型)在数据类型上更匹配。


三、Schema 探查:动手前的安全网

AI Agent 操作数据库最大的风险不是 SQL 写错,而是在不了解表结构的情况下直接执行 DDL

映射表中 7 条 Schema 探查映射,构成了 AI 操作前的标准预案:

用户:"在 orders 表上加个 discount_rate 列"
  ↓
Step 1: "What columns does this table have?"
  → SELECT column_name, data_type, nullable FROM all_tab_columns
    WHERE owner = :schema AND table_name = :tbl
    ORDER BY column_id

  (发现已有一个 DISCOUNT 列——用户可能只是不知道)

Step 2: "Primary keys?"
  → SELECT cols.column_name FROM all_constraints c
    JOIN all_cons_columns cols ON c.constraint_name = cols.constraint_name
    WHERE c.owner = :schema AND c.table_name = :tbl
    AND c.constraint_type = 'P'

Step 3: "Table DDL?"
  → SELECT DBMS_METADATA.GET_DDL('TABLE', :tbl, :schema) FROM DUAL

最后才执行 ALTER TABLE——而且会带着完整上下文:
"orders 表已有 DISCOUNT 列(NUMBER),确认要新增 discount_rate?"

没有这套 Schema 探查,AI 直接写 ALTER TABLE orders ADD (discount_rate NUMBER)——然后因为列名冲突或者不了解现有约束而失败。映射表强制 AI 先看后动。ORDER BY column_id 在这里不是装饰——它保证了列按建表时的顺序展示,与 DESCRIBE 命令的输出一致,DBA 看着更顺手。


四、看似简单的日期模式:暗藏的性能陷阱

映射表中的 6 个日期过滤模式,乍看都是基础操作,但每个都体现了生产环境的最佳实践:

-- 本周(周一起始)
WHERE col >= TRUNC(SYSDATE, 'IW')
  AND col <  TRUNC(SYSDATE, 'IW') + 7

-- 本月
WHERE col >= TRUNC(SYSDATE, 'MM')
  AND col <  ADD_MONTHS(TRUNC(SYSDATE, 'MM'), 1)

这些日期模式都用了 >= ... AND < 的半开区间,而非 BETWEEN。这不是风格偏好——BETWEEN 包含两端边界,当时间列带时分秒时,BETWEEN '2026-06-01' AND '2026-06-30' 会漏掉 6 月 30 日当天的所有非零时分秒数据(如 2026-06-30 14:30:00)。

映射表对此的处理一丝不苟:

写法 问题 映射表用
BETWEEN 含右边界,丢失当天后续时间数据 不用
TRUNC(col) 在 WHERE 里 函数包裹列,索引失效 不用
col >= ... AND col < ... 半开区间 + 列不包裹 = 走索引 ✅ 始终用这个

还要注意一个小细节:TRUNC(SYSDATE, 'IW') + 7 是用整数加法跳到下周一零点——ISO 周从周一开始,加 7 天正好跨越一整周。而「本月」用的是 ADD_MONTHS(TRUNC(SYSDATE, 'MM'), 1),因为月份天数不固定,不能简单地用 + 30+ 31,必须借助 ADD_MONTHS 保证精确。

这些细节 AI 不可能从训练数据中区分出优先级——训练数据里四种写法都有,而且各有适用场景。映射表给了明确的选择标准。


五、消歧指南:比 SQL 模板更重要的东西

映射表有一张独特的对照表——「模糊需求 → 追问澄清」:

模糊表述 应追问
“Show me employees” 哪个 schema?全部列?只查在职的?
“Recent orders” 今天?本周?最近 30 天?
“Big tables” 按行数?按存储空间?阈值多少?
“Slow queries” 按总耗时?平均耗时?CPU 时间?
“Delete old records” 哪个表?什么算「旧」?硬删除还是软标记?

AI 最危险的倾向不是写错 SQL,而是在需求模糊时自己猜一个答案。

取最后一条作例子。用户说「帮我把旧数据删了」。没有映射表的 AI 可能直接生成:

DELETE FROM orders WHERE created_date < SYSDATE - 365;

提交后发现有 300 万行被删——用户说的「旧」可能是指已归档的、标记为废弃的,而不是按时间一刀切。

加载了消歧指南后,AI 的标准行为应该是五连问:

  1. 哪张表?
  2. 「旧」的定义?(30 天?一年?status = 'ARCHIVED'?)
  3. 物理删除还是软标记(is_deleted = 1)?
  4. 要不要先 SELECT COUNT(*) 确认影响行数?
  5. 有没有外键依赖?

追问逻辑是跨语言通用的。中文提问「帮我清理一下旧数据」同样触达这条消歧规则——大模型不需要英文关键词匹配,它读的是语义结构。这一点在后面的中文优化章节会进一步展开。


六、安全约束:嵌入在 Skill 中的操作纪律

映射表不仅给出正确的 SQL,还对危险操作嵌入了操作纪律。以 KILL SESSION 为例:

-- Kill the session (requires ALTER SYSTEM privilege)
-- IMPORTANT: always confirm with user before killing; this is irreversible
ALTER SYSTEM KILL SESSION ':sid,:serial#' IMMEDIATE;

下面紧跟着一条 Agent rule

Agent rule: Never execute ALTER SYSTEM KILL SESSION
without explicit user confirmation.
Validate both SID and SERIAL# before constructing the command.

这不是 SQL 语法——是操作纪律,直接写入 Skill 文件中。它的效果是:无论 AI Agent 的 system prompt 怎么写、无论后面的对话上下文怎么变,只要加载了这个文件,KILL SESSION 之前一定会确认

类似的隐式安全约束还体现在:

  • dba_hist_* 查询前的 Diagnostics Pack 许可警告
  • Schema 探查放在 DDL 操作之前(先读后写)
  • WHERE username IS NOT NULL 过滤系统进程(避免误杀后台会话)

这些约束不是靠 prompt 工程能保证的——prompt 可以被长对话冲淡。嵌入 Skill 文件的规则,每次加载都重新生效。这是 Skill 系统区别于 prompt 指令的根本优势。


七、实战:从一句话到完整诊断

假设用户在凌晨两点发来一条消息:「数据库有点慢,帮我看下」。

不加载映射表:AI 大概率生成 SELECT * FROM v$session WHERE status = 'ACTIVE',然后把几百行输出丢回去。

加载映射表后,AI 按照文件中「从全局到具体」的诊断链路,三步完成:

第一步:等待事件总览

SELECT event, COUNT(*)
FROM   v$session
WHERE  wait_class != 'Idle'
GROUP  BY event
ORDER  BY 2 DESC;

输出:enq: TX - row lock contention: 34 sessions waiting

第二步:定位阻塞源

SELECT blocker.sid, blocker.username, blocked.sid,
       blocked.seconds_in_wait, obj.object_name
FROM   v$session blocked
JOIN   v$session blocker ON blocked.blocking_session = blocker.sid
LEFT   JOIN v$lock lk ON lk.sid = blocker.sid
                      AND lk.type = 'TM'
                      AND lk.lmode > 0
LEFT   JOIN dba_objects obj ON obj.object_id = lk.id1
WHERE  blocked.blocking_session IS NOT NULL
ORDER  BY blocked.seconds_in_wait DESC;

输出:SID 287 (用户 BATCH_JOB) 阻塞了 34 个会话,被锁对象是 orders 表,已阻塞 23 分钟。

第三步:查看阻塞者正在跑什么

SELECT sq.sql_text
FROM   v$session s
JOIN   v$sql sq ON s.sql_id = sq.sql_id
              AND s.sql_child_number = sq.child_number
WHERE  s.sid = 287;

诊断结论:「SID 287 的一个批量更新事务持有 orders 表锁,阻塞了 34 个会话,已持续 23 分钟。该事务正在执行全表更新——建议确认是否可以终止。」

这个诊断路径来自映射表中多条查询的隐式排序——从宏观等待事件到微观阻塞链路,文件本身的组织方式就是诊断流程。


八、中文场景:让映射表说中文

前面七节都在讲映射表「有什么」和「怎么用」。但有一个很现实的问题被绕过去了——当前这张表全是英文

8.1 英文映射表在中文团队的摩擦

当前 nl-to-sql-patterns.md 的所有 trigger phrase 都是英文:

"What's waiting in the database?"
"Show me the slowest queries"
"who is locking what"

而实际对话中,用户和 Agent 之间大概率是中文:

“数据库在等什么?”
“谁把这张表锁了?”
“昨天那个定时任务为什么失败了?”

这中间的翻译依赖的是什么?大模型内在的跨语言理解能力。 没有一条显式的中文 → SQL 映射路径。大多数时候大模型能自行对应——毕竟 “slow queries” 和 “慢查询” 语义完全对齐——但在一些细微的、文化特定的表达上就可能跑偏。

举个例子:中文 DBA 习惯说「hang 住了」、「卡死了」、「锁等待超时」——这三个短语指向的是同一个场景(阻塞诊断),但字面上没有任何一个和 “blocking session” 直接对应。如果 Agent 没有在映射表中见过这些中文说法,它可能不知道该执行那套阻塞诊断 SQL。

8.2 两种优化方案

方案一:中文触发词并行映射(推荐,改动最小)

直接在现有英文模式旁边增加中文触发短语列:

Natural Language (EN) 自然语言 (CN) Oracle SQL Pattern
“What’s waiting in the database?” “数据库在等什么” / “当前等待事件” SELECT event, COUNT(*) FROM v$session WHERE wait_class != 'Idle' GROUP BY event ORDER BY 2 DESC
“who is locking what” “谁锁了表” / “阻塞源头” / “hang住了” SELECT blocker.sid ... FROM v$session blocked JOIN v$session blocker ON ...
“Show me the slowest queries” “最慢的查询” / “慢SQL” / “TOP SQL” ORDER BY elapsed_time DESC on v$sql
“Records from the last 7 days” “最近一周的数据” / “过去7天” WHERE created_date >= SYSDATE - 7

关键不是穷举所有中文说法,而是列出同一语义下的高频同义表述。以「阻塞」为例,在生产环境中可能出现的中文说法包括:

  • 谁锁了表?
  • 查一下阻塞
  • 锁等待
  • 卡住了 / hang 住了
  • 这个会话为什么在排队?
  • enq: TX - row lock contention

一个 Agent 看到以上任何一句话,都应该路由到同一套阻塞诊断 SQL。把这几条中文说法写进映射表,就从「靠大模型自己猜」变成了「精确匹配」。

方案二:中文分词 + 关键词路由

在 Agent 框架层做一层轻量中文分词,提取关键词后路由到映射表类别:

中文输入:"帮我看看哪些表没有主键"
    ↓ 分词
关键词:表、主键、没有
    ↓ 匹配类别
Tables Without Primary Keys
    ↓ 执行对应 SQL

这个方案的好处是不需要逐条写中文映射——只要关键词覆盖模式够全,就能收敛到正确的类别。但也引入了额外的分词和匹配逻辑,不如方案一直接。

建议:用方案一作为基础,从最高频的两个板块(性能诊断 + 锁与阻塞)开始落地。方案二作为后续优化方向。

8.3 中文消歧:模糊性比英文更高

第五章讲的消歧指南跨语言通用,但中文有一个特性值得专门关注:中文在数据库运维场景下的模糊性往往比英文更高。

中文表述 可能的含义(危险等级各异) 必须追问
“数据库慢了” 整体慢 / 某个 SQL 慢 / 某个时段慢 / 网络慢 什么现象?什么时间段?影响范围?
“表太大了” 行数多 / 存储占用大 / 索引膨胀 按行数还是按存储?阈值多少?
“帮我清理一下” DELETE / TRUNCATE / DROP / 归档 / 分区清理 哪种操作?哪个表?保留条件?
“这个用户” schema 名 / OS 用户名 / 应用连接用户 / 大小写? 具体用户名是什么?

尤其是「清理」这个词——英文对应多个完全不同危险等级的操作:DELETE(可回滚)、TRUNCATE(不可回滚的 DDL)、DROP(直接删表)、归档(INSERT INTO archive + DELETE)。Agent 如果在「清理」这一步猜错了,后果是灾难性的。

所以中文消歧指南需要比英文版更细——不能只在模糊词出现时追问一次,而要对「清理」「删掉」「处理一下」这类动作动词做强制二次确认,无论上下文看起来多清晰。

8.4 落地策略:分步扩展

在实际工程中,不需要一次性给所有板块都配上中文映射。按使用频率和风险分批推进:

优先级 板块 理由
P0 性能诊断(等待事件 / 慢查询) 最高频,占日常排障 80%
P0 锁与阻塞 应急场景,错一步就多卡 N 分钟
P1 Schema 探查 日常操作,AI 做 DDL 前的安全检查
P1 定时任务 运维例行,失败排查高频
P2 空间 / 存储 低频,错了也只是数字不准确
P2 用户 / 权限 安全相关但操作频率低

8.5 最终的映射表长什么样

将上述思路落地后,扩展版映射表的每个 section 会变成三列结构:

Performance and Diagnostics Questions

Natural Language (EN) 自然语言 (CN) Oracle SQL Pattern
“What’s waiting in the database?” “数据库在等什么” / “当前等待事件” / “等待事件分布” SELECT event, count(*) FROM v$session WHERE wait_class != ‘Idle’ GROUP BY event ORDER BY 2 DESC
“Show me the slowest queries” “最慢的SQL” / “慢查询TOP N” / “耗时最长的查询” SELECT sql_text, elapsed_time/1e6 elapsed_sec FROM v$sql ORDER BY elapsed_time DESC FETCH FIRST 20 ROWS ONLY
“Which queries use the most CPU?” “CPU最高的SQL” / “CPU密集型查询” ORDER BY cpu_time DESC on v$sql

Agent 加载 skill 时同时获得中英文触发路径——英文保留作为 fallback,中文提供第一优先级匹配。不需要额外的路由层,不需要改框架代码,只加一列。


九、这张表不做什么

明确边界和明确能力同样重要:

不适用的场景:

  • 分析型 SQL:环比、同比、运行合计、多层次 CTE——需要 sql-patterns.md
  • 性能调优决策:该加什么索引、Hint 怎么用——需要 sql-tuning.md
  • 跨数据库:所有视图都是 Oracle 专有(v$dba_),MySQL/PostgreSQL 无法复用

加载时的注意事项:

  • dba_hist_* 系列查询需要 Diagnostics Pack 许可
  • v$sessiondba_users 需要 SELECT ANY DICTIONARY 或对应系统权限
  • KILL SESSION 需要 ALTER SYSTEM 权限
  • all_scheduler_* 视图仅显示当前用户有权限看到的 Job——不是全局视图

十、总结

这张 13KB 的小文件,本质上是一本给 AI Agent 读的「Oracle 运维速查手册」:

它提供什么 它不提供什么
锁诊断 → v$session 自连接 怎么写窗口函数
慢查询 → v$sql + AWR 两套方案 索引该加在哪列上
定时任务 → dba_scheduler_* 三表关联 SQL 语法教程
模糊需求 → 追问清单 业务逻辑建议
危险操作 → 安全约束规则 性能调优策略

它的设计哲学很简单:AI 不需要背下 Oracle 的全部系统视图,只需要知道「用户说锁 → 查 v$session.blocking_session」、「用户说慢 → 查 v$sql 按 elapsed_time 排序」。

对于每天跟 Oracle 打交道的工程师,把这个skill配进 Agent,相当于让 AI 默认自带一个中级 DBA 的排障直觉——知道查哪张表、用哪个列、怎么关联。而在此基础上再加以中文优化,则让这张表从「英文手册」真正变成「中文团队的生产力工具」。


📎 源文件:https://github.com/oracle/skills/blob/main/db/agent/nl-to-sql-patterns.md

Logo

小龙虾开发者社区是 CSDN 旗下专注 OpenClaw 生态的官方阵地,聚焦技能开发、插件实践与部署教程,为开发者提供可直接落地的方案、工具与交流平台,助力高效构建与落地 AI 应用

更多推荐