更新日期:2026 年 10 月 21 日。本文件只保留迁移后的语义 SQL 与统一计划两个专题,不代表高级篇已完成。文件名中的 18/19 仅为历史编号,正式章号在基础篇完成后确定;本轮不扩写高级内容。
| 章节 | 单章入口 |
|---|---|
| 高级专题:语义 SQL 与虚拟业务表 | 正文 |
| 高级专题:SQL 与 DSL 怎样进入统一执行计划 | 正文 |
前面已经讨论分阶段与多维分析。本章回到第 4 章的客户排名例子,保留 LLM 熟悉的 SQL 写法,仍然查询同一个语义模型。业务用户继续用自然语言提问,改变的是 LLM 提交请求的方式。
这条路线是:自然语言 → 语义 SQL → DSL 或内部查询计划 → 物理 SQL → 数据库执行。
以下语法仍是教学约定,重点看前后两个 SQL 分别面向什么,以及它们怎样转换。
第 1 章的 SQL 查询 invoices 和 customers,需要自己关联、筛选有效状态、把分转为元。
语义 SQL 可以改为查询 SalesInvoiceQueryModel。它代表第 4 章约定的业务查询面,公开客户 ID、客户名称、开票日期和单张有效发票金额;真实表名和关联方式由语义模型提供。
这张虚拟表由语义层的 SQL 入口识别,不要求复制数据或创建同名数据库视图。LLM 可以复用已有的 SQL 语法经验,但仍需读取查询元数据,确认字段含义与可用操作。
下面沿用第 4 章的语义字段:
SELECT
customerId,
customerName,
SUM(salesAmount) AS totalSales
FROM SalesInvoiceQueryModel
WHERE invoiceDate >= '2025-06-01'
AND invoiceDate < '2025-07-01'
GROUP BY customerId, customerName
ORDER BY totalSales DESC, customerId ASC
LIMIT 3;
它与第四章的 DSL 表达相同意图:按客户累计六月金额,降序取前三名。对照关系如下:
| SQL 部分 | 对应的查询表达 |
|---|---|
FROM SalesInvoiceQueryModel |
model 指定语义模型 |
SELECT |
columns,包含金额求和及别名 |
WHERE |
聚合前条件 slice |
GROUP BY |
groupBy |
ORDER BY |
orderBy |
LIMIT |
limit 指定返回条数 |
这里没有物理表 JOIN、有效状态条件或分转元表达式:这些规则仍由语义模型提供。SUM(salesAmount) 只负责把已经以元表达的单票金额按客户汇总。
flowchart LR
A[语义 SQL] --> B[解析、绑定与校验]
B --> C[DSL 或内部查询计划]
C --> D[编译物理 SQL]
D --> E[数据库执行]
解析器将 SELECT、WHERE 等结构整理成语法树(AST);绑定阶段确认表名对应哪个语义模型、字段是否公开,以及 totalSales 来自哪个表达式。
随后检查类型、聚合与权限,确定过滤和计算发生的阶段。上表只是本例的对应关系,不能把任意 SQL 都按关键词机械换成 JSON 键名。
本例可以转换为第 4 章的 JSON 请求,再沿用相同的执行规则;复杂查询可能直接形成内部计划,不一定生成公开的 JSON 文件。
本例的单票金额可以求和,第 3 章的平均每张发票金额则需要按当前分组重新计算,不能把各客户的平均值当作普通金额再次相加。
因此,语义 SQL 入口仍要保留指标依赖、聚合方式与计算上下文。计算指标怎样引用,也需要由查询协议说明。保留 SQL 写法可以减少语法适配的负担,业务定义仍需明确。
本例只涉及选列、行过滤、分组、求和、排序和返回条数。子查询、CTE、窗口函数、跨语义模型关联及自定义函数,还需要由入口明确声明支持范围。
SQL 语法合法,不代表该入口就能执行。遇到不支持的写法,应返回明确诊断;若现有 DSL 能等价表达,可以在含义和权限不变的前提下改写,否则说明暂不支持。
本章改变的是查询入口:LLM 用 SQL 表达意图,语义层仍依据同一套业务定义校验和编译。前一个 SQL 面向虚拟业务表,后一个面向物理数据库。
统一计划专题继续看两个入口怎样共用执行计划,避免各自维护一套业务规则。
如果系统分别为 SQL 和 DSL 编写销售额公式、状态过滤和权限处理,两条路线很容易在一次修改后产生差异。双入口的价值,是让不同写法最终使用同一套业务定义和执行规则。
第 4 章的 DSL 和语义 SQL 专题,都要求同一模型、同一时间、同一客户粒度和同一销售额口径。
| 查询要素 | 语义 SQL | Query DSL |
|---|---|---|
| 金额汇总 | SUM(salesAmount) AS totalSales |
columns 中相同表达式 |
| 六月范围 | invoiceDate >= ... AND invoiceDate < ... |
slice 的 [) 区间 |
| 客户粒度 | 按客户 ID 和名称分组 | groupBy 列出两个字段 |
| 排序 | 金额降序,客户 ID 升序 | -totalSales、customerId |
| 返回范围 | LIMIT 3 |
limit: 3 |
下面用简化逻辑计划表示它们共同的含义。这是解释用的步骤,实际内部节点名称由引擎决定:
从 SalesInvoiceQueryModel 取数
→ 应用模型规则和当前用户的数据范围
→ 筛选 2025-06-01 ≤ 开票日期 < 2025-07-01
→ 按客户 ID、名称分组,求销售额合计
→ 按合计降序、客户 ID 升序排序
→ 返回前 3 行
这是逻辑含义,优化器可以调整实际执行顺序,前提是保留语义和权限约束。
flowchart LR
A[语义 SQL] --> B[SQL 解析与名称绑定]
C[Query DSL] --> D[结构解析与字段绑定]
B --> E[共同的语义校验与逻辑计划]
D --> E
E --> F[物理规划与方言编译]
F --> G[执行并返回结果]
M[模型定义与身份上下文] --> E
SQL 前端负责解析语法树,DSL 前端负责读取结构化请求。两个入口随后进入共同的模型、类型、聚合和权限检查,再由执行层规划关联、展开计算,生成底层查询。
第 4 章的 DSL 描述一次语义模型查询;用于分阶段分析的 DSL 还可以组织多个步骤及中间结果。它们的结构和能力不同,不能只因都使用 JSON 风格就互相替换。
CLI 或 API 还需要模型、命名空间、分页等调用信息。调用外壳负责把请求送到正确入口,不等于内部执行计划。
内部表示常称为 IR,用来保存解析、绑定后的查询含义。它可以包含多阶段计算和数据流,通常比公开的单模型请求更丰富。因此,SQL 与 DSL 共用引擎,不要求“所有 SQL 都先翻译成同一份公开 JSON”。
先固定数据快照、模型版本、当前身份和查询参数,再比较两条路线的字段、条件、聚合阶段、结果数值和顺序。
只比较“金额都一样”还不够:客户名称相同可能合并了不同客户,少一个条件也可能恰好不影响当前数据。可以沿用第 2 章的同额发票、月底记录和无明细发票作为边界样例,再加入不同身份的数据范围验证。
在双入口实现中,两种写法引用同一未公开字段,也应受到相同限制。核对目标是查询含义与约束一致,生成的 SQL 文本可以因别名或优化策略而不同。
SQL 容易被熟悉数据库的人理解,也方便对接 SQL 工具,但需要维护解析器、名称绑定、函数与方言支持范围。DSL 的结构便于约束和校验,调用方则要学习字段和表达方式。
共用模型可以减少业务规则的重复维护,解析适配、错误诊断和回归验证仍然需要分别完成。只有确实需要 SQL 客户端或分析人员入口时,才值得承担第二套前端的成本。
统一执行计划把“怎样写查询”与“怎样解释和执行查询”分开。输入可以不同,业务含义、权限约束和核对标准应保持一致。
性能与一致性另设专题,系列顺序在基础篇完成后确定。