做过数据平台的人多半遇到过这样的场景:业务方拿着一张报表来质疑数字,你翻了三层脚本才找到指标是在哪个环节被算错的,结果发现问题出在两张名字几乎一样的表上,一张是全量快照,一张是增量明细,开发的人早就离职了,文档一个字都没有。这类问题的根源,往往不是技术能力不够,而是从一开始就没有建立 SQL 规范。数据治理如果只停留在喊口号、建组织、开评审会,而不落到具体的规范上,治理效果会大打折扣。

没有规范的 SQL 会给数据治理埋下哪些雷
规范缺失带来的第一个问题是命名混乱。同一个团队里,有人建的表叫 dwd_order_detail_di,有人建的是 order_detail_df,还有人直接叫 t_order。命名风格不统一还是小事,更严重的是同名不同义:两张都叫订单明细的表,一张包含退款单,一张不包含,下游用的时候没人说得清该用哪张。时间一长,仓库里堆满了语义模糊的表,新人接手时的第一反应就是再建一张自己的表,恶性循环由此开始。
第二个问题是口径不一致。GMV 这个指标,市场部算的是含退款的成交额,财务部算的是剔除退款后的净额,两个团队各自在脚本里写了一段聚合逻辑,字段名都叫 gmv。表面上数据对得上字段,实际上数字永远差一截,这种问题排查起来极其耗时,因为校验逻辑分散在上百个脚本里,没有任何集中管理的出口。
第三个问题是脚本本身不可维护。存储过程三千行,一个 SELECT 嵌套七层子查询,没有注释,没有分区过滤,全表扫描跑六个小时。数据治理要求可追溯、可优化、可下线,可这三点的前提都是代码能被读懂。脚本写成一团乱麻,血缘分析工具解析不出来,僵尸表永远删不掉,存储成本和计算成本只增不减。
一套可落地的 SQL 规范应该包含什么
规范要能落地,必须具体到可以执行的层面,而不是一句模糊的大家注意命名。一套比较完整的 SQL 规范通常包含四个部分:分层规范、命名规范、开发规范和变更规范。
分层规范先解决表放哪儿的问题。典型做法是按 ODS、DWD、DWS、ADS 划分层级,规定每一层的职责边界:ODS 只做贴源存储,DWD 做明细清洗,DWS 做轻度汇总,ADS 面向报表和应用。层次清晰之后,依赖方向就明确了,下游表只能引用同层或上层的数据,禁止反向依赖,这样血缘关系才不会乱成一团。
命名规范解决表和字段怎么起名的问题。表的命名建议采用分层前缀加业务域加内容描述加更新频率的结构,例如 dwd_trade_order_detail_di,看名字就知道这张表属于哪一层、哪个业务域、按天增量更新。更新频率后缀要统一约定,比如 _df 表示全量、_di 表示日增量、_hi 表示小时增量,团队内部不许各造各的。字段层面则要求布尔字段用 is_ 前缀,时间字段用 _time 或 _date 结尾,金额字段统一使用分为单位的整数并注明,避免精度问题引发口径纠纷。
开发规范的核心条目
开发规范是日常写得最多的部分,重点包括:所有查询大表必须带分区过滤条件;JOIN 时小表放右边或使用广播;禁止 SELECT *,必须显式列出字段;INSERT 覆盖写必须指定列清单;每段脚本头部写明作者、用途、依赖表和输出表。下面是一段符合规范的脚本示例:
-- 作者: data_team
-- 用途: 订单明细日增量清洗
-- 依赖: ods.ods_trade_order_di
-- 输出: dwd.dwd_trade_order_detail_di
INSERT OVERWRITE TABLE dwd.dwd_trade_order_detail_di PARTITION (dt = '${bizdate}')
SELECT
order_id,
user_id,
order_amount,
is_refund,
pay_time
FROM ods.ods_trade_order_di
WHERE dt = '${bizdate}'
AND order_status IN ('PAID', 'FINISHED');
别小看头部注释这一条,当治理平台做血缘解析和影响分析时,脚本级的依赖声明能大幅提升准确率,也让人工排查成本直线下降。
规范如何被强制执行而不是停留在文档里
规范最大的敌人是被写在 Wiki 里然后无人问津。要让它真正生效,需要把规范转变成流程中的强制卡点。第一个抓手是代码评审,所有 SQL 必须经过 MR 合入,评审清单里逐项检查命名、分区过滤、字段注释,不符合的直接打回。第二个抓手是自动化校验,用工具在提交阶段扫描 SQL,命中规则就阻断合并,常用的方案是基于 SQL 解析器(如 SQLGlot 或 sqllineage)写规则引擎,识别全表扫描、SELECT 星号、跨层依赖等问题。
下面是一段用 Python 做简单校验的思路示例,检查 SELECT 语句里是否包含星号和分区过滤:
import re
def check_sql(sql: str) -> list:
problems = []
# 检查 SELECT *
if re.search(r'select\s+\*', sql, re.IGNORECASE):
problems.append('禁止使用 SELECT *')
# 检查分区过滤条件
if not re.search(r"where\s+.*dt\s*=", sql, re.IGNORECASE):
problems.append('缺少分区字段过滤条件')
return problems
issues = check_sql("SELECT * FROM dwd.dwd_trade_order_detail_di")
print(issues) # 输出两条违规信息
第三个抓手是把规范和平台能力绑定。建表时通过模板自动生成分区、生命周期和注释,元数据平台对超过保留期的表自动提醒负责人处置,指标口径统一注册到指标字典,脚本里只能引用已注册的指标。当开发者发现遵守规范比绕过规范更省事时,规范才算真正扎下了根。
治理效果如何衡量
规范执行一段时间后,需要用指标验证效果。常用的观察维度包括:核心表命名合规率、脚本血缘解析成功率、重复建设表数量、僵尸表清理数量、指标口径冲突次数。建议每月产出一份治理报告,把数字变化和具体案例放在一起,既能向上证明治理价值,也能向团队反馈改进方向。规范不是一次性的文档,而是随业务演进的活制度,定期回顾和修订同样重要。