117 lines
4.1 KiB
Markdown
117 lines
4.1 KiB
Markdown
---
|
||
name: sql-review
|
||
description: 当一条 Spark SQL 已经生成、通过 guardrails 并准备展示或执行前使用。它基于 sql_context 静态检查字段引用、alias、join key、数据膨胀、重复聚合、时间过滤、转化顺序、GROUP BY、空值、类型和写入风险,只报告问题,不直接改 SQL。
|
||
---
|
||
|
||
# SQL Review(SQL 静态评审)
|
||
|
||
## 目标
|
||
|
||
在 SQL 执行前做质量检查,发现可能导致数字错误、执行失败或性能风险的问题。评审只报告风险和建议,不负责直接改写 SQL。
|
||
|
||
## 输入
|
||
|
||
```yaml
|
||
sql: "待评审的 Spark SQL"
|
||
sql_context:
|
||
status: CONTEXT_READY
|
||
sql_guard:
|
||
status: PASS
|
||
logic_plan:
|
||
status: PLANNED
|
||
```
|
||
|
||
如果没有 `sql_context`,也可以继续做基础结构检查,但必须报告一个 HIGH 风险:缺少上下文,无法保证字段和 join 正确。
|
||
|
||
## 检查项
|
||
|
||
1. 字段引用:每个 `alias.column` 是否存在于 `sql_context.fields`。
|
||
2. alias:SQL 是否发明了 context 中没有的 alias。
|
||
3. join key:ON 条件是否匹配 context 中固定的 join。
|
||
4. join 基数:1:N 或 N:N join 是否会造成数据膨胀。
|
||
5. 指标公式:聚合表达式是否符合 logic plan 和 context。
|
||
6. 重复聚合:同一指标是否被重复 sum/count。
|
||
7. 时间过滤:事实表是否缺少必要时间或分区过滤。
|
||
8. 时间边界:T-1 完整日是否使用左闭右开窗口。
|
||
9. 转化顺序:后置事件是否满足前置事件之后发生。
|
||
10. GROUP BY:非聚合输出列是否都在 group by 中。
|
||
11. 空值策略:join key 和度量字段是否需要 coalesce 或保留策略。
|
||
12. 类型匹配:字符串日期、字符串金额是否需要 cast。
|
||
13. 写入风险:INSERT 目标列、overwrite 确认、分区覆盖范围是否明确。
|
||
14. 执行成本:是否存在无分区裁剪的大表全扫、笛卡尔积、窗口无 partition。
|
||
|
||
## 时间边界检查
|
||
|
||
当需求为“近 N 天按 T-1 完整日”且字段是 timestamp/date-like:
|
||
|
||
推荐:
|
||
|
||
```sql
|
||
event_time >= date_sub(current_date(), N)
|
||
AND event_time < current_date()
|
||
```
|
||
|
||
风险写法:
|
||
|
||
```sql
|
||
event_time BETWEEN date_add(current_date(), -N) AND date_add(current_date(), -1)
|
||
```
|
||
|
||
如果 SQL 使用风险写法,至少标为 `MEDIUM`;如果会明显漏掉结束日期白天数据,标为 `HIGH`。
|
||
|
||
## 转化顺序检查
|
||
|
||
对注册、付费、激活、下单等漏斗指标,必须检查后置事件是否在前置事件之后。若口径是“注册后付费”,SQL 必须有等价约束:
|
||
|
||
```sql
|
||
pay_time >= register_time
|
||
```
|
||
|
||
如果 SQL 先按用户取 `MIN(pay_time)`,再和 `register_time` 比较,而没有在聚合前加入 `pay_time >= register_time`,标为 `HIGH` 或 `MEDIUM`,因为这可能漏算注册后仍然完成付费的用户。
|
||
|
||
## 输出格式
|
||
|
||
```yaml
|
||
sql_review:
|
||
verdict: PASS | FAIL
|
||
highest_severity: NONE | LOW | MEDIUM | HIGH
|
||
summary: "一句话结论"
|
||
findings:
|
||
- id: R1
|
||
severity: HIGH | MEDIUM | LOW
|
||
check: reference_integrity | join_cardinality | metric_formula | time_filter | time_boundary | conversion_order | group_by | type_check | write_risk | performance | other
|
||
location: "SQL 片段或行号"
|
||
message: "问题描述"
|
||
recommendation: "建议修复方向"
|
||
notes:
|
||
- "评审假设"
|
||
```
|
||
|
||
## 用户可见摘要
|
||
|
||
除了 YAML,必须输出:
|
||
|
||
```markdown
|
||
## SQL Review
|
||
- 结论:PASS / FAIL
|
||
- 最高风险:NONE / LOW / MEDIUM / HIGH
|
||
- 已检查:字段引用、join、GROUP BY、时间窗口、转化顺序、空值、类型、性能
|
||
- 主要风险:...
|
||
- 是否可交付:...
|
||
```
|
||
|
||
## 严重程度
|
||
|
||
- `HIGH`:会导致数字错误、执行失败、越权写入或违反策略,必须阻断。
|
||
- `MEDIUM`:大概率可跑,但有性能、稳定性或边界风险,需要用户接受。
|
||
- `LOW`:风格或可维护性问题。
|
||
|
||
只要存在 HIGH,`verdict` 就是 `FAIL`。只有 LOW/MEDIUM 时,可以把风险交给用户决定是否接受。
|
||
|
||
## 禁止行为
|
||
|
||
- 不要直接改 SQL;只输出发现和建议。
|
||
- 不要凭直觉审字段,必须对照 `sql_context`。
|
||
- 不要因为 SQL 能通过 guardrails 就跳过业务正确性审查。
|
||
- 不要忽略写入模式,尤其是 `INSERT OVERWRITE`。
|