《快缩短网址·suo.run:以RBAC为引,产品经理的数据库逻辑设计之旅》

一、序章:当产品经理开始写 ER 图
“快缩短网址”上线第 127 天,后台权限体系终于迎来第一次大重构。作为产品负责人,我把会议室的落地窗当成白板,用马克笔写下三个词:简洁、可演进、可解释。
这三个词,后来成了我们数据库逻辑设计的北极星。

二、为什么 B 端产品经理必须懂数据库
在 suō.run,我们每日生成 300 万条短链访问日志。若数据模型稍有冗余,三个月后就会演化成一场灾难。
招聘 JD 里那句“了解主流数据库原理”不再是加分项,而是生死线。产品经理若不能亲手画出 ER 图,就无法在评审会上说服后端“为什么这张表必须第三范式,而那张表可以反范式”。
三、从业务到模型:一次 RBAC 的拆解
1. 需求抽象
• 组织:可嵌套,支持集团—子公司—部门。
• 角色:全局唯一,支持继承与互斥。
• 权限:粒度到按钮级,可动态绑定菜单。
• 用户:一人多岗,可跨组织。
2. 生命周期判断
• 组织与用户:永久存储,逻辑删除。
• 角色与权限:永久存储,版本化。
• 登录会话:30 天过期,物理删除。
3. 极简 ER 图(白板版)
[组织]——[用户]——[角色]——[权限]
菱形为关系,矩形为实体,椭圆里只保留主键。
四、范式与反范式的舞蹈
1. 第一范式:原子性
把“联系方式”拆成 email、phone 两列,拒绝 CSV 式字符串。
2. 第二范式:主键依赖
用户表不再携带组织名称,仅保留 org_id 作为外键。

3. 第三范式:传递依赖
角色描述单独建表 role_meta,避免在 user_role 里冗余。
4. 反范式:性能妥协
短链访问日志按天分表,冗余存储长链摘要,减少回表。

五、落地清单:从逻辑到物理
1. 命名规范
• 表:snake_case,复数形式,如 users、roles。
• 字段:主键 id,外键 xxx_id,时间戳 created_at/updated_at。
2. 字段类型
• 枚举:tinyint,附注释说明。
• JSON:PostgreSQL jsonb,存权限点数组。
• 金额:decimal(10,2),拒绝 float。
3. 索引策略
• 覆盖索引:(user_id, role_id) 联合索引,减少回表。
• 分区键:log_date,按日分区,90 天后冷存。
六、尾声:产品经理的 SQL 仪式感
上线前夜,我在命令行敲下:
EXPLAIN ANALYZE
SELECT u.id, u.username, r.name
FROM users u
JOIN user_roles ur ON u.id = ur.user_id
JOIN roles r ON r.id = ur.role_id
WHERE u.org_id = 42;
当执行计划里出现 Index Only Scan,我知道,这场重构稳了。
七、彩蛋:给后来者的一封信
如果你今天才加入 suō.run,请把这篇文章当作地图,而不是终点。
数据库设计没有银弹,只有一次次在业务、性能、成本之间优雅地平衡。
愿你在下一次需求评审时,也能在白板上潇洒地画出那张 ER 图,然后轻声说:
“这张表,第三范式;那张表,为了 10 毫秒,反范式。”