Oracle SQL 优化知识库:构建方案与价值评估
文档类型 :方案宣讲(讲清楚为什么做、怎么做、优缺点)
适用场景 :团队评审、技术分享、方案汇报
配套文档 :
plans/DESIGN-QDRANT-INTEGRATION.md(技术设计)、plans/SPRINT-PDF-INGESTION.md(实施计划)数据来源:所有数字来自实际工具输出(ingest_report.md / 落盘测试日志),可追溯
一、为什么需要构建知识库
1.1 问题:纯 LLM 优化 SQL 的根本缺陷
SQLAdvisor 的核心功能是"用 LLM 优化 Oracle SQL"。但直接让 LLM 改写 SQL 有一个根本缺陷:
LLM 的优化建议没有权威依据,全凭模型自身记忆。
具体表现:
| 问题 | 后果 |
|---|---|
| LLM 可能编造 Oracle 不支持的语法/hint | 生成的 SQL 在 Oracle 上报错或无效 |
| LLM 的优化建议泛泛而谈("加索引"、"改写子查询") | 缺乏具体到 Oracle 版本的准确指导 |
| LLM 不知道 Oracle 12c 的特定特性(如自适应优化、SQL Plan Baseline) | 错过版本专属的优化机会 |
| 不同 LLM、不同会话给出不一致的建议 | 优化质量不稳定,不可复现 |
| 无法解释"为什么这样优化" | 用户不敢采纳,优化建议缺乏可信度 |
本质:LLM 是个"学过很多但记不准"的顾问。没有权威知识约束,它会把模糊记忆当事实输出------这在数据库优化这种"差一个 hint 就差 10 倍性能"的场景下是危险的。
1.2 知识库解决什么
把 Oracle 官方文档 (SQL Tuning Guide,724 页权威指南)结构化成知识库,让 LLM 在改写 SQL 时先检索权威依据,再生成建议:
没有知识库: 用户SQL → LLM(凭记忆)→ 优化建议(可能编造)
有了知识库: 用户SQL → 检索官方文档 → LLM(基于权威依据)→ 优化建议(有出处)
核心价值:把 LLM 从"凭记忆的顾问"变成"查了手册的顾问"。
1.3 为什么选 Oracle 12c SQL Tuning Guide
| 理由 | 说明 |
|---|---|
| 权威性 | Oracle 官方出版(E49106-14, July 2017),是 Oracle SQL 调优的权威指南 |
| 系统性 | 24 章 + 附录,覆盖优化器、统计信息、执行计划、访问路径、连接、并行、SQL Profile 等全链路 |
| 版本匹配 | 项目测试库是 Oracle 18.4 XE(12c 架构延续),文档适用 |
| 结构清晰 | 有完整目录(outline),便于按章节抽取,天然适合知识库构建 |
| 公开可得 | Oracle 官网公开 PDF,无版权障碍(内部使用) |
二、如何构建知识库
2.1 整体方案:PDF → 结构化知识 → 向量库
2.1.1 全景流程图
核心思路:把一本 724 页的 PDF 官方手册,经过 提取 → 切片 → 抽取 → 验证 → 导出 五步,变成可被 Agent 检索、可追溯、抗编造的结构化知识库。
┌─────────────────────────────────────────────────────────────────┐
│ Oracle 官方 PDF │
│ 《SQL Tuning Guide》12c Release 1 │
│ 724 页 · 24 章 · outline 1027 条目录 │
└────────────────────────────┬────────────────────────────────────┘
│
┌──────────────▼──────────────┐
│ ① 文本提取(Stage A) │ pdfplumber 逐页提取
│ + 章节归属解析 │ pypdf outline 解析目录
└──────────────┬──────────────┘
│ 724 页原文(697 有效 + 27 跳过)
│ 每页带 section_path(如 "Ch.11 Histograms")
┌──────────────▼──────────────┐
│ ② 章节切片(Stage B) │ 按 outline 章节边界分组
│ token 感知切块 │ 目标 1200 token/片,重叠 150
└──────────────┬──────────────┘
│ 308 个 chunks
│ 覆盖 1-24 章 + 附录全部
┌──────────────▼──────────────┐
│ ③ LLM 智能抽取(Stage C) │ 每片喂 GLM-4-flash
│ 强制 source_quote │ 要求输出结构化 JSON
│ + 自动 quote 校正 │ 每条必须带原文引用
└──────────────┬──────────────┘
│ 1031 条原始条目
│ 4 类:规则/解释/语法/示例
┌──────────────▼──────────────┐
│ ④ 五层验证 + 去重清洗 │ L0 完整性 / L1 一致性
│ (详见 §2.3) │ L2 语义 / L3 反向 / L4 人工
│ + 字段清洗 + 强去重 │ 剔除 102 条无法回溯的
└──────────────┬──────────────┘
│ 847 条验证后的知识
│ 带质量分级(verified/disputed)
┌──────────────▼──────────────┐
│ ⑤ 多目标导出(Stage E) │ 一次构建,四处消费
└─┬─────────┬──────────┬───────┴──────────┬──────────┘
▼ ▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌──────────────┐ ┌──────────────┐
│rules.json│ │ SQLite │ │ Markdown │ │ Qdrant │
│ 372 条 │ │ 847 行 │ │ 33 个章节文件 │ │ 847 points │
│ 规则引擎 │ │ 结构化 │ │ 人工审查 │ │ 向量检索 │
│ 源 │ │ 查询 │ │ │ │ (Agent RAG) │
└─────────┘ └─────────┘ └──────────────┘ └──────────────┘
2.1.2 数据流转:每一步的输入、处理、输出
| 步骤 | 输入 | 关键处理 | 输出 | 淘汰/损耗 |
|---|---|---|---|---|
| ① 文本提取 | 724 页 PDF | pdfplumber 逐页提文字;pypdf 解析 outline 建"页→章节"映射(含前向继承:章节标题后的所有页继承该章节,直到下个标题) | 697 页有效文本 + 27 页跳过(封面/目录/扉页) | 27 页低信息密度页(合理跳过,有清单可查) |
| ② 章节切片 | 697 页文本 | 按 outline 章节边界分组;章节内按 token 累积切(1200 token/片,150 重叠防截断);跳过 <100 token 的过短片(封面/分隔页) | 308 个 chunks | 4 个过短 chunk 跳过 |
| ③ LLM 抽取 | 304 个有效 chunks | 每个 chunk 喂 GLM-4-flash,要求:识别优化规则/语法/示例/概念 → 输出结构化 JSON → 每条必须带 source_quote(≥20 字原文精确引用);同时跑 quote 自动校正(LCS 算法把改写过的引用对齐回原文) |
1031 条原始条目 | 1 个 chunk 抽取超时失败(附录 A 索引指南,显式记录) |
| ④ 验证去重 | 1031 条原始条目 | L1:回原文验证 source_quote(90.1% 通过,剔除 102 条无法回溯的编造);L2:LLM 二次校验忠实度;字段清洗(修复类型错放);强去重(标题归一化相等合并) | 847 条验证后条目 | 102 条 L1 剔除 + 82 条强重复合并 + 4 条 quote 不可验证 |
| ⑤ 多目标导出 | 847 条最终条目 | safety 闸门过滤 example_sql(145 条危险 SQL 过滤);并行导出 4 种格式 | rules.json(372) + SQLite(847) + Markdown(33 文件) + Qdrant(847 points) | 145 条 example_sql 被 backend 安全闸门过滤(保留条目本体,只清空 example_sql 字段) |
2.1.3 关键技术决策(为什么这么做)
| 决策 | 选择 | 为什么不选另一方案 |
|---|---|---|
| 切片粒度 | 1200 token/片 + 150 重叠 | 太小(如 500 token):切碎语义,LLM 抽取上下文不足;太大(如 3000 token):超出 LLM 有效注意力,抽取质量下降。重叠 150 防"建议被切到两半" |
| 切片边界 | 按 outline 章节边界优先,章节内再按 token | 纯滑窗(无视章节):会把"直方图"和"统计信息"混在一个 chunk,LLM 抽取混乱;按章节优先:语义连贯 |
| 抽取模型 | GLM-4-flash(OpenAI 兼容) | 用规则/正则提取:无法理解语义,抓不住"建议"这种主观表述;用大模型(GPT-4):成本高 10 倍,且 flash 对结构化抽取够用 |
| 防编造机制 | 强制 source_quote + 自动回溯 | 不强制引用:LLM 会用自己的话概括,无法验证是否忠实原文;强制引用让每条知识都可追溯到 PDF 页码 |
| embedding 模型 | GLM embedding-3(dim 2048) | BGE-M3(本地):需下载 2GB 模型,HuggingFace CDN 在当前网络不可达;GLM 在线 API:国内可访问,已验证可用 |
| 向量库 | Qdrant(独立 collection) | 不用向量库(纯关键词检索):抓不住语义相似("全表扫描" vs "table access full");Qdrant 独立 collection:不污染现有 oracle_best_practices |
| 去重策略 | 标题归一化强去重(不用语义去重) | 语义去重(embedding 相似度):需加载 embedding 模型,慢且有误判风险;强去重:确定性强,可复现 |
| 导出多目标 | 一次构建导出 4 种格式 | 只导向量库:规则引擎/人工审查/结构化查询都用不了;多目标:同一份知识适配不同消费场景 |
2.1.4 质量闸门分布(数据在哪里被淘汰)
从 1031 条原始抽取到 847 条最终条目,每一步的淘汰都有据可查(不静默丢弃):
1031 条原始抽取
│
├─ L1 剔除 -102 条(source_quote 无法回溯原文 → 疑似编造)
│ 清单: l1_mismatches.jsonl(可审查每条为何被剔)
│
├─ 强去重合并 -82 条(标题归一化后重复)
│
└─▶ 847 条进入最终产物
│
├─ L2 disputed 253 条(保留但标 ⚠️,不剔除------降级可见)
│ 清单: l2_disputes.jsonl
│
└─ safety 过滤 145 条 example_sql(条目保留,只清空示例 SQL 字段)
原因: 含 DDL/多语句等,被 backend 四层安全闸门拦截
原则 :所有淘汰/降级都在报告和清单文件中显式列出,不折叠为泛化的"success"。任何一条被剔除的知识都能查到原因。
2.2 五阶段构建管线
| 阶段 | 做什么 | 工具 | 产出 |
|---|---|---|---|
| A. 文本提取 | PDF 每页提取文字 + 解析目录建立章节归属 | pdfplumber + pypdf | 724 页原文(697 有效页 + 27 跳过页) |
| B. 章节切片 | 按章节边界 + token 长度切成知识片段 | tiktoken(1200 token/片,150 重叠) | 308 个 chunks,覆盖 1-24 章全部 |
| C. LLM 抽取 | 每个片段让 GLM-4 提取结构化知识(规则/语法/示例) | GLM-4-flash(OpenAI 兼容) | 1031 条结构化条目 |
| D. 去重清洗 | 标题去重 + 字段清洗 + 严重度归一 | Python 规则 + 启发式 | 847 条最终条目 |
| E. 多目标导出 | 同时导出 4 种格式供不同场景消费 | httpx + SQLite + json | rules.json / SQLite / Markdown / Qdrant |
2.3 五层质量验证(核心:防止 LLM 编造)
构建知识库最大的风险是 LLM 在抽取过程中编造内容(把模糊记忆当文档内容输出)。为此设计了五层验证:
| 层 | 验证什么 | 怎么验 | 结果 |
|---|---|---|---|
| L0 完整性 | PDF 有没有漏页、产物数量一致 | 机械计数:dedup=SQLite=Qdrant=847 | ✓ 全过 |
| L1 一致性(防编造底座) | 每条知识能不能回溯到 PDF 原文 | 强制 source_quote 字段,自动回原文做子串匹配 |
90.1% 通过(剔除 102 条无法回溯的) |
| L2 语义校验 | 抽取是否忠实原文(非语义篡改) | 第二轮 LLM 独立评判每条 | 582 verified + 253 disputed(全保留降级) |
| L3 反向覆盖 | PDF 要点有没有被遗漏 | 反向抽样:每章抽页列要点,查是否被覆盖 | 70% 覆盖,0 critical 遗漏 |
| L4 人工抽检 | 最终可信度 | 50 条人工对照 PDF 原文核对 | 96% 全对(48/50) |
关键设计------L1 强制回溯 :每条抽取的知识必须带一句 source_quote(≥20 字,必须是 PDF 原文精确子串)。系统自动回 PDF 原文验证这句引用是否真实存在------这一层拦住了绝大多数 LLM 编造。
2.4 最终知识库内容(847 条)
| 类型 | 数量 | 说明 | 示例 |
|---|---|---|---|
| optimization_rule | 372 | 优化规则(可被规则引擎/RAG 用) | "索引列避免函数,或用函数索引 FBI" |
| explanation | 350 | 概念解释 | "什么是直方图、成本估算原理" |
| syntax_doc | 95 | 语法说明 | "CREATE INDEX 语法、DBMS_STATS 调用" |
| example_sql | 30 | 完整示例 SQL(已过安全闸门) | 频率直方图生成示例 |
每条知识都带:
source_page(PDF 页码,可追溯)source_quote(原文精确引用)category(INDEX/STATISTICS/JOIN/OPTIMIZER 等 14 类)severity(INFO/WARN/ERROR,optimization_rule 专属)quality_flag(verified/disputed,质量分级)
2.5 构建耗时与成本(真实数据)
| 项 | 耗时 | 说明 |
|---|---|---|
| 文本提取(724 页) | ~10 分钟 | pdfplumber |
| LLM 抽取(308 片段) | ~3.5 小时 | GLM-4-flash,含网络重试 |
| L1-L4 验证 | ~1.5 小时 | 自动 + 人工抽检 |
| 总计 | ~5 小时 | 一次性构建,后续可增量 |
| GLM 调用次数 | ~3000 次 | 抽取 + 二次校验 |
| 成本 | 数元级别 | glm-4-flash 单价低 |
三、知识库如何被使用
3.1 集成到 Agent 主优化流程
用户提交 SQL 后,Agent 在让 LLM 改写之前,先检索知识库找相关权威依据:
用户: SELECT * FROM orders WHERE UPPER(customer_name) = 'ACME'
│
Agent 自动检索知识库(用 SQL 语义匹配)
│
▼
命中: [INDEX] 索引列上避免函数(或用函数索引 FBI)
"WHERE UPPER(name)='X' 会使 name 上的普通 B-tree 索引失效"
来源: Oracle 12c SQL Tuning Guide p.211
│
▼
注入到 LLM prompt: <knowledge> 索引列避免函数... </knowledge>
│
▼
LLM 生成变体: CREATE INDEX idx_cust_upper ON orders(UPPER(customer_name));
SELECT * FROM orders WHERE UPPER(customer_name) = 'ACME';
(变体的 rationale 引用了知识库依据,不再是凭空建议)
3.2 多种使用方式
| 方式 | 场景 | 怎么用 |
|---|---|---|
| Agent 自动接地(已集成) | 主优化流程 | 调 /api/optimize,RAG 自动注入,用户无感 |
| 向量检索(Qdrant) | 语义查询"如何优化 X" | 按 SQL/关键词检索,返回最相关的 top-N 条 |
| 结构化查询(SQLite) | 精确查某类规则/某页内容 | SQL 查询 oracle_12c_kb.db,按 category/severity 过滤 |
| 人工查阅(Markdown) | 学习/审查 | 33 个按章节组织的 topics-*.md,每条带原文引用 |
| 规则引擎源(rules.json) | 补充 AST 规则 | 372 条 optimization_rule,backend rules.json 兼容格式 |
四、使用知识库的优点
4.1 优化建议有权威依据(核心价值)
| 维度 | 无知识库 | 有知识库 |
|---|---|---|
| 建议来源 | LLM 模糊记忆 | Oracle 官方文档原文 |
| 可追溯性 | 无法验证 | 每条建议带 PDF 页码 + 原文引用 |
| 版本准确性 | 可能混淆版本 | 锁定 Oracle 12c 特性 |
| 可信度 | 用户不敢采纳 | 用户可查原文确认 |
4.2 LLM 编造被有效抑制
L1 强制回溯机制(每条知识必须引用 PDF 原文)让知识库本身抗编造。Agent 基于这样的知识库生成建议,等于给 LLM 加了"必须引用手册"的约束。
4.3 知识可复用、可审计
构建一次(5 小时),多处消费:
- Agent 主流程用(RAG 接地)
- 未来 chatbot 用(语义问答)
- 规则引擎用(372 条规则)
- 人工查阅用(Markdown)
- 质量可审计(五层验证,每条可追溯到 PDF 页)
4.4 构建过程可复现、可增量
- 全流程代码化(
ingestion包),可重新构建 - 断点续跑(大文件中断可恢复)
- 第二本 PDF(SQL Language Reference,1920 页)同管线,配置已就绪
五、使用知识库的缺点与局限
诚实评估------知识库不是银弹,以下局限必须知晓。
5.1 检索质量受 query 构造影响(当前主要痛点)
问题:用原始 SQL 做 embedding query 效果一般。SQL 的语法噪音(SELECT/FROM/WHERE)淡化了优化意图。
实例 :查 SELECT * FROM employees WHERE UPPER(name)='SMITH',理想是命中"函数索引"那条规则,实际命中的是泛化的"Querying Table Information"(score 0.53)。
影响:注入 LLM 的知识不一定是最相关的,优化建议的针对性打折。
缓解方向 :改用 rule_findings(AST 规则发现文本)或 SQL 特征描述做 query,而非 raw SQL。
5.2 引入额外延迟和依赖
| 代价 | 量级 | 说明 |
|---|---|---|
| 每次优化多 ~0.5s | GLM embedding 0.45s + Qdrant 检索 0.05s | 用户感知不明显,但高并发下累积 |
| 依赖 GLM embedding API | 在线服务 | API 不可达时降级为纯 LLM(不阻塞,但失去接地) |
| 依赖 Qdrant 服务 | 独立进程 | Qdrant 宕机时同样降级 |
5.3 知识库覆盖率非 100%
- L3 反向覆盖率 70%(非 80% 门槛):抽样发现的 191 个 minor 遗漏(多为细分要点),无 critical 遗漏,但意味着部分次要知识点未被独立抽取
- L4 人工抽检 96%(2 条字段错放):质量高但非完美
- 253 条 disputed(L2 有疑虑):保留但标 ⚠️,使用前建议人工核对
5.4 构建前期投入大
- 5 小时构建(含 LLM 抽取 + 验证)------虽然是一次性,但比"直接用 LLM"重得多
- 需要 PDF 原文------必须先有权威源文档
- 需要 GLM API 额度------抽取+校验约 3000 次调用
5.5 embedding 方案的运维复杂度
- 知识库用 GLM embedding(dim 2048),与 backend 原有 BGE-M3(dim 1024)不兼容
- 必须按 collection 选择 embedding 模型,配置不能错(错了维度不匹配,查询失效)
- 切换 embedding 模型需重建整个向量库
5.6 仅覆盖一本 PDF(当前)
当前只构建了 SQL Tuning Guide(724 页)。SQL Language Reference(1920 页,语法大全)尚未构建(管线已就绪,待启动)。语法类问题目前知识库覆盖不足。
六、总结:值不值得做
6.1 价值矩阵
| 维度 | 评分 | 说明 |
|---|---|---|
| 解决编造问题 | ★★★★★ | L1 强制回溯 + L2 二次校验,从源头抑制 LLM 编造 |
| 提升建议可信度 | ★★★★★ | 每条建议可追溯到 Oracle 官方文档页码 |
| 构建成本 | ★★★☆☆ | 5 小时 + 3000 次 API,一次性投入,可接受 |
| 检索质量 | ★★★☆☆ | 当前 query 构造偏弱,有改进空间 |
| 运维复杂度 | ★★★☆☆ | 多了 Qdrant + GLM embedding 依赖,但有降级容错 |
| 覆盖范围 | ★★★★☆ | 724 页已覆盖调优核心,1920 页语法待补 |
6.2 适用与不适用场景
适合用知识库:
- 数据库优化这种"权威性要求高、错误代价大"的领域
- 有权威源文档(官方手册、标准规范)可抽取
- 用户需要"为什么这样优化"的可解释性
- 优化建议需要版本准确(Oracle 12c 特性)
不适合用知识库:
- 没有权威文档的领域(LLM 记忆已是最佳来源)
- 一次性快速验证(构建 5 小时太重)
- 实时性要求极高(检索增加 0.5s 延迟)
- 领域知识频繁变化(知识库需频繁重建)
6.3 结论
值得做。对于 SQLAdvisor 这类数据库优化工具,知识库把 LLM 从"不可控的顾问"变成"查了手册的顾问"------这是从"能用"到"敢用"的关键一步。5 小时构建成本相比"用户不敢采纳优化建议"的代价是划算的。
当前主要改进方向是检索质量 (query 构造)和覆盖范围(第二本 PDF),这些是增量优化,不影响"知识库本身值得构建"的基本判断。
附录:核心数字速查(全部实测,可追溯)
| 指标 | 数值 | 来源 |
|---|---|---|
| PDF 页数 | 724 | pypdf 实测 |
| 知识片段数 | 308 | chunker 产出 |
| 原始抽取条目 | 1031 | extractor 产出 |
| 最终知识条目 | 847 | extracts_dedup.json |
| optimization_rule | 372 | type 统计 |
| L1 一致性通过率 | 90.1%(929/1031) | l1_verified.jsonl 计数 |
| L2 verified | 582 | quality_flag 统计 |
| L2 disputed(保留降级) | 253 | quality_flag 统计 |
| L3 反向覆盖率 | 70.0%(449/641) | l3_coverage_gaps.json |
| L3 critical 遗漏 | 0 | l3_coverage_gaps.json |
| L4 人工抽检通过率 | 96%(48/50) | l4_audit_50.csv |
| 四产物一致性 | ✓(dedup=SQLite=Qdrant=847) | 实测 |
| 构建总耗时 | ~5 小时 | 实际运行 |
| Agent 测试 | 14/14 passed(41.45s) | 落盘测试日志 |