2. Schema标准与规范:命名规范、数据类型、字段注释与生命周期管理
大家好,我是老张。今天咱们聊聊Schema标准与规范。说实话,我见过太多团队在数据治理上栽跟头,最后发现根子都在Schema规范没立住。你想想看,一个数据仓库里,表名叫t1、tmp_xxx、test_final_v2,字段名全是a、b、c,注释要么没有要么写“这个字段很重要”——这数据谁敢用?
所以这一章,我把Schema规范拆成四个核心维度来讲:命名规范、数据类型规范、字段注释规范、生命周期管理规范。每个维度我都会结合自己踩过的坑,给你讲清楚“为什么”和“怎么做”。
核心观点:Schema规范不是束缚,而是数据资产的“通用语言”。没有规范,数据治理就是空中楼阁。
2.1 命名规范:让表名和字段名“自解释”
命名规范这事儿,我个人的习惯是:好的命名不需要注释。你看到ods_order_di,就知道这是订单明细增量表;看到dim_user_sd,就知道是用户维度的全量快照表。这才是命名该有的样子。
2.1.1 表名规范
表名我建议采用层级_主题_业务描述_频率的格式。举个例子:
-- 规范格式:{层级}_{主题}_{业务描述}_{频率后缀}
ods_order_di -- ODS层,订单主题,明细增量
dwd_trade_ord_di -- DWD层,交易主题,订单明细增量
dim_user_sd -- DIM层,用户主题,缓慢变化维
ads_sales_1d -- ADS层,销售主题,每日汇总
频率后缀这块,我建议统一用:
| 后缀 | 含义 | 示例 |
|---|---|---|
| _di | 增量(incremental) | ods_order_di |
| _df | 全量(full) | dim_user_df |
| _1d | 天级汇总 | ads_sales_1d |
| _sd | 缓慢变化维 | dim_product_sd |
| _tmp | 临时表(需标注TTL) | tmp_etl_check |
我曾经踩过的坑:有次接手一个项目,表名叫test_20230101_final_v3,里面存的是生产数据。我问负责人这表干嘛的,他说“我也不记得了”。从那以后,我强制团队所有临时表必须带tmp_前缀,并且设置7天自动清理。血的教训啊。
2.1.2 字段名规范
字段名我建议用小写+下划线,不要用驼峰,更不要用中文。你想想看,userName和user_name在Hive里大小写敏感,查起来多麻烦。
几个核心原则:
- 业务含义优先:
order_amount比amt好,create_time比ct好 - 避免保留字:别用
date、name、type当字段名,加个前缀如order_date、user_name - 布尔字段用is_开头:
is_active、is_deleted,一眼就知道是布尔值 - 时间字段统一后缀:
_time(精确到秒)、_date(精确到天)
-- 推荐写法
create table dwd_trade_ord_di (
order_id string comment '订单ID',
user_id string comment '用户ID',
order_amount decimal(18,2) comment '订单金额',
order_status string comment '订单状态',
is_paid boolean comment '是否已支付',
create_time timestamp comment '创建时间',
update_time timestamp comment '更新时间'
);
2.1.3 分区字段规范
分区字段的命名,我个人建议统一用dt(天级分区)和hh(小时级分区)。别搞什么partition_date、p_date,团队里每个人写法都不一样,查询的时候还得猜。
-- 推荐的分区定义
create table ods_order_di (
order_id string,
user_id string,
amount decimal(18,2)
)
partitioned by (dt string comment '天分区,格式yyyyMMdd')
stored as parquet;
小技巧:分区字段不要放在业务字段里。我见过有人把dt既当分区又当业务字段,结果查询时where dt = '20240101'走分区裁剪,但where dt >= '20240101'就全表扫描了。分区字段就老老实实只做分区用。
2.2 数据类型规范:选对类型,省一半存储
数据类型这块,说白了就是别用大炮打蚊子。我见过有人把年龄字段设成BIGINT,把状态码设成STRING,存储浪费不说,查询性能还差。
| 业务场景 | 推荐类型 | 不推荐 | 原因 |
|---|---|---|---|
| 订单金额、价格 | DECIMAL(18,2) | FLOAT/DOUBLE | 浮点数有精度丢失,算钱会出大问题 |
| 用户ID、订单ID | STRING | BIGINT | ID可能带前缀或字母,STRING更通用 |
| 状态码(0/1/2) | TINYINT | STRING/INT | TINYINT只占1字节,INT占4字节 |
| 年龄、数量 | INT | BIGINT | INT够用就别用BIGINT,省存储 |
| 时间戳 | TIMESTAMP | STRING | TIMESTAMP支持时间函数,STRING还得解析 |
| 布尔值 | BOOLEAN | TINYINT(0/1) | BOOLEAN语义更清晰 |
我个人的经验:DECIMAL类型一定要指定精度。我见过DECIMAL不写精度,默认DECIMAL(10,0),结果金额小数位全被截断了。线上跑了一个月才发现,修复数据花了整整三天。所以,DECIMAL(18,2)写清楚,别偷懒。
2.3 字段注释规范:注释是给“未来的你”看的
字段注释这事儿,我特别有感触。你想想看,半年后你回头看自己写的表,如果没有注释,你还能记得status字段的0、1、2分别代表什么吗?
我建议注释遵循以下格式:
-- 推荐注释格式
字段名 类型 注释内容
order_status STRING '订单状态:0-待支付,1-已支付,2-已发货,3-已完成,4-已取消'
is_deleted BOOLEAN '逻辑删除标记:true-已删除,false-未删除'
create_time TIMESTAMP '记录创建时间,精确到毫秒'
几个硬性要求:
- 每个字段都必须有注释,没有例外。我团队里,建表语句没有注释直接打回重写。
- 枚举值要写清楚含义,别只写“状态”,要写“0-待支付,1-已支付”。
- 单位要标注,比如金额单位是“元”还是“分”,时间单位是“秒”还是“毫秒”。
- 计算逻辑要说明,比如
order_amount是“商品金额+运费-优惠券抵扣”。
我曾经遇到的事:有个表amount字段注释只写了“金额”,结果业务方和开发对“金额”的理解差了10倍——业务方以为是“元”,开发存的是“分”。最后报表数据全错了,查了三天才找到根子。从那以后,我要求所有金额字段必须标注单位,比如amount DECIMAL(18,2) COMMENT '订单金额,单位:元'。
2.4 生命周期管理规范:数据不是越老越值钱
很多团队有个误区,觉得数据存得越久越好。其实不然。你想想看,三年前的日志数据,既没人查又占存储,还拖慢查询性能,留着干嘛?
我建议按数据层级制定不同的保留策略:
| 数据层级 | 保留周期 | 说明 |
|---|---|---|
| ODS(原始数据) | 30-90天 | 原始日志,一般保留3个月,超过后归档到冷存储 |
| DWD(明细数据) | 6-12个月 | 清洗后的明细,保留半年到一年 |
| DWS(汇总数据) | 2-3年 | 轻度汇总,保留时间长一些 |
| ADS(应用数据) | 永久保留 | 报表和指标,按需保留,一般长期保存 |
| DIM(维度数据) | 永久保留 | 维度表,保留历史版本即可 |
| TMP(临时表) | 7天 | 临时表必须设置TTL,到期自动清理 |
具体怎么实现?我建议用分区裁剪+定时任务:
-- Hive示例:删除30天前的ODS分区
alter table ods_order_di drop partition (dt < '20240101');
-- 或者用脚本定期执行
-- 伪代码:delete_partitions('ods_order_di', 30)
小建议:临时表一定要设TTL。我习惯在表名里加个日期后缀,比如tmp_etl_check_20240101,然后写个定时任务,扫描所有tmp_开头的表,超过7天的自动删除。这样既不会误删,也不会让临时表变成“永久表”。
2.5 规范落地的“最后一公里”
规范写出来容易,落地难。我个人经验是,光靠文档和口头要求没用,得靠工具和流程来卡。
几个落地建议:
- 建表模板化:把规范做成建表模板,开发人员只能填空,不能改结构
- 自动化检查:用脚本或工具检查表名、字段名、注释是否符合规范,不符合的打回
- Code Review:每次建表或改表,必须经过Review,重点看命名和注释
- 定期审计:每个月跑一次审计脚本,找出不合规的表,推动整改
总结一下:命名规范让表“自解释”,数据类型规范省存储提性能,字段注释规范让数据可理解,生命周期管理规范让数据不“腐烂”。这四个维度缺一不可,共同构成了Schema治理的基石。