OceanBase SQL 审查助手
面向 OceanBase(MySQL 兼容模式)的 SQL 静态审查技能。不连接数据库、不执行 SQL, 纯静态分析 SQL 文本,输出「问题 → 依据 → 改写建议」三段式报告。
何时使用
- 用户粘贴 SQL / DDL,要求找问题、做优化、评审、上线前检查
- 用户提到 OceanBase、OB、分区表、租户、慢查询、执行计划、索引没生效
- 用户对
EXPLAIN结果存疑,需要反推 SQL 写法上的问题
不适用:需要真实执行计划或真实数据分布才能回答的问题(如「这条查询实际耗时多少」 「统计信息是否过期」)——本技能只做文本层面判断,这类问题请明确告知用户需要连接数据库验证。
执行流程
第 1 步:跑一遍静态检查(默认动作)
脚本零依赖,Python 3.8+ 即可运行:
# 审查单个文件
python scripts/audit_sql.py path/to/queries.sql
# 只看高危问题
python scripts/audit_sql.py path/to/queries.sql --severity high
# 机器可读输出,便于接入流水线
python scripts/audit_sql.py path/to/queries.sql --format json
# 从标准输入读取
cat queries.sql | python scripts/audit_sql.py -
# 查看全部规则清单
python scripts/audit_sql.py --list-rules
退出码:0 = 未发现达到阈值的问题,1 = 发现问题,2 = 执行错误(可直接用于 CI 卡点)。
脚本输出已包含问题定位(行/列)、问题说明与改写建议,不要重复实现规则, 也不要在脚本之外重新逐条检查同一类问题。
第 2 步:结合表结构复核(如果用户提供了 schema)
脚本无法得知表结构,因此以下判断需要用户补充 schema 后复核:
| 规则 | 需要确认的信息 |
|------|---------------|
| OB-OB-002 / OB-OB-011 | 表是否为分区表、分区键是哪些列 |
| OB-OB-005 | 表的写入频率(全局索引写放大与写入量成正比) |
| OB-OB-013 | 表的数据量级(去重代价) |
| OB-SQL-020 / OB-SQL-021 | 索引键长限制、列的实际字符集 |
| OB-OB-014 | 优化器是否把子查询改写成了 semi-join |
若用户未提供 schema,在报告中把这些条目标记为「需结合实际表结构确认」, 不要直接断言为缺陷。
第 3 步:输出报告
使用 references/report-template.md 的结构输出。 报告必须包含:
- 结论摘要 —— 各级别问题数量 + 是否建议上线
- 问题清单 —— 按严重级别排序,每条含:规则编号、位置、问题、依据、改写建议
- 改写后的 SQL —— 对 high / critical 级问题,直接给出可用的改写版本
- 需要用户确认的事项 —— 依赖 schema 或运行时数据才能定论的条目
规则体系
规则分两套编号,与 references/ 下的文档一一对应:
OB-SQL-0xx—— 通用 SQL 规范与性能规则(任何 MySQL 系数据库都适用),见 references/sql-rules.mdOB-OB-0xx—— OceanBase 特有规则(分布式 / 分区 / 索引形态),见 references/oceanbase-specific.md
严重级别定义:
| 级别 | 含义 | 处理建议 |
|------|------|---------|
| critical | 会导致数据错误或全表误操作 | 必须修,不修不允许上线 |
| high | 会导致索引失效、锁范围过大或结果不正确 | 上线前必须修 |
| medium | 性能风险,需要结合数据量评估 | 建议修 |
| low | 优化建议、架构层面的提醒 | 有余力再优化 |
| info | 风格与规范类建议 | 可选 |
改写手法速查见 references/rewrite-patterns.md。
使用示例
例 1:审查一段查询
用户:
SELECT * FROM order_detail
WHERE DATE(created_at) = '2026-01-01'
AND amount = '100'
ORDER BY RAND();
助手:先运行 python scripts/audit_sql.py,然后按报告模板输出。要点:
OB-SQL-001用了SELECT *—— 表结构一改结果集就漂移,且无法命中覆盖索引OB-SQL-003DATE(created_at)包裹了索引列 —— 分区裁剪与索引都失效OB-SQL-004amount = '100'数值列与字符串比较 —— 隐式类型转换,索引失效OB-SQL-010ORDER BY RAND()—— 全量随机排序OB-SQL-015没有 LIMIT —— 结果集大小不可控
改写后:
SELECT order_id, user_id, amount, created_at
FROM order_detail
WHERE created_at >= '2026-01-01'
AND created_at < '2026-01-02'
AND amount = 100
ORDER BY created_at DESC
LIMIT 200;
例 2:评审建表语句
用户:CREATE TABLE t (id BIGINT, ts DATETIME, payload JSON);
助手:
OB-SQL-023没有主键 —— OceanBase 会用隐藏主键,影响聚簇组织与查询性能OB-OB-006含时间列但未分区 —— 建议按时间分区,便于归档与分区裁剪OB-SQL-020JSON 列参与索引 —— 索引键长受限,建议改用独立的检索方案
改写后:
CREATE TABLE t (
id BIGINT NOT NULL AUTO_INCREMENT,
ts DATETIME NOT NULL,
payload JSON,
PRIMARY KEY (id)
) PARTITION BY RANGE COLUMNS (ts) (
PARTITION p2026q1 VALUES LESS THAN ('2026-04-01'),
PARTITION pmax VALUES LESS THAN (MAXVALUE)
);
例 3:慢查询定位
用户:「OB 上一个分页接口越来越慢,LIMIT 1000000, 20。」
助手:OB-SQL-008 深分页 —— 数据库要先扫描并丢弃前 100 万行。
改用游标分页(WHERE id > :last_id ORDER BY id LIMIT 20),
若必须支持跳页,改用覆盖索引 + 延迟关联。
注意事项
- 脚本是静态检查:它看不到索引、统计信息和数据分布,结论需要与
EXPLAIN交叉验证 - 对 OceanBase 特有规则,若用户没提供 schema,请明确说明「该结论需结合实际表结构确认」
- 不要在报告中编造用户没有提供的表结构、索引名或执行计划信息
- 改写建议要给完整可执行的 SQL,不要只说「建议加索引」这种空话
微信扫一扫