最小化不是删数据,而是让每个字段都能说出谁在读它。
一、六个月日志里的一次对账
2026 年 8 月,他准备给数据库续费,顺手把 6 个月的应用日志和查询日志导出来,想看看哪些表最占空间。对完之后发现一件更值得处理的事:78 个个人字段里有 23 个从未被任何功能、报表或导出读取,连一次 SELECT 都没有出现过。
以下情境为教学假设,人物、引语和数字不代表经核实的真实案例。
其中一个叫 company_size 的字段,是上线第一天从模板里抄来的。表单上有,数据库里有,后台从来没有展示过,报表也没有按它分过组。它从上线那天一直躺到现在,直到这次对账才被看见。
他先做了一个粗略估计:23 ÷ 78 = 29.5%,接近三成的字段可以删除。真正让他犹豫的不是比例,而是这 23 个字段分散在多张表里,其中 3 张表还被 2 个报表和 1 个导出脚本引用。
他不是没想过直接删。但删列是不可逆操作,2 个报表的 SQL 里出现过这些表名,1 个导出脚本还 SELECT *。任何一个地方没改干净,第二天的定时任务就会失败。
于是他换了一个顺序:先停写,观察两周,再删列。这个顺序后来被证明比「找到就删」慢两周,但比「删完回滚」快得多。
停写的第一天,他关掉了注册表单里的几个营销字段。表单短了一截,转化没有变化;这让他意识到,这些字段不仅没人读,连填的人也不在意。
一个字段如果回答不出「谁在什么功能里读它」,它就不该继续被收集。
二、二十三个字段分三类
最小化常被理解成「少收一点」,但「少」没有判据。可执行的判据只有一个:每个字段都能指到一个具体的读取方——某个页面、某个接口、某个报表,或者某条导出语句。
23 个字段按「为什么没人读」分成三类,处理方式并不相同。
| 类别 | 数量 | 典型字段 | 为什么没人读 |
|---|---|---|---|
| 营销 | 9 | 公司规模、行业、职位、来源渠道 | 表单模板自带,只写不读 |
| 调试 | 8 | 设备型号、时区、请求标识、UA | 上线初期排查用,问题消失后没删 |
| 历史遗留 | 6 | 旧版本迁移留下的别名列 | 数据搬完了,列还留着 |
| 合计 | 23 | — | — |
营销类的 9 个字段最尴尬:它们本来是为了「以后做分层运营」收集的,但一个人做产品,分层运营这件事从来没排进过日程。收集的成本当天就付了,收益一直停在「以后」。
调试类的 8 个字段有明确的历史使命。上线初期,他靠设备型号和时区复现过几个只在特定环境出现的 bug;bug 修完之后,这些字段既没有进报表,也没有进告警,只是继续被写进每一行事件。
历史遗留类的 6 个字段是迁移的副产品。字段改名时为了兼容旧代码保留了别名列,旧代码下线后别名列没有被清理,于是同一份数据在两张表里各存一份,读的永远是新的那份。
三类字段的共同点是「写入路径还在,读取路径已经消失」。判断一个字段是否属于这一类,不能问作者「它有用吗」,只能查日志「它被读过吗」。
统计读取次数时有一个坑:SELECT * 不会在查询日志里留下具体列名。他先用 SELECT * 的语句定位到 2 个报表和 1 个导出脚本,再逐个改成显式列名,才拿到可信的按列统计。
三、七十八乘四的目的限定矩阵
比「有没有人读」更根本的问题是「允许谁读」。他把 78 个字段和 4 类目的摆成一张矩阵:行是字段,列是服务、计费、分析、营销,每个格子只有「允许」和「拒绝」两种值。
| 目的 | 典型字段 | 判断问题 |
|---|---|---|
| 服务 | 邮箱、项目名、评论正文 | 不读它,功能是否无法完成 |
| 计费 | 金额、币种、发票号 | 是否是开票或对账必需 |
| 分析 | 事件、会话标识 | 能否用聚合数据替代 |
| 营销 | 邮箱、来源渠道 | 是否有单独同意且可撤回 |
矩阵一共 78 × 4 = 312 格。允许 96 格,占 96 ÷ 312 = 30.8%;拒绝 216 格,占 216 ÷ 312 = 69.2%。也就是说,近七成的「字段—目的」组合在一开始就不该存在。
允许和拒绝的边界不是「技术上能不能」,而是「这个目的下是否必需」。邮箱在服务目的下是登录凭证,必需;在营销目的下是触达渠道,只有在单独同意之后才允许。同一个字段在不同目的下的答案可以不同,这正是矩阵要逐格填的原因。
逐格填写听起来机械,但每一格都要回到一个具体问题:这个目的下不读它,功能会不会坏。答案写进格子,等于给未来的自己留了一份判断记录;半年后再问同一个字段,不用重新争论。
一个字段只能挂一个主目的。主目的决定它的保留期、共享方和删除方式;其他目的下的使用要么被拒绝,要么需要额外的依据。把邮箱同时标成「服务」和「营销」的主目的,等于让两个保留期互相打架。
主目的的写法要具体到功能名,不能写「产品改进」这种万能词。写「项目页展示」可以判断真假,写「产品改进」则任何字段都能塞进去,矩阵立刻失去约束力。
矩阵填完之后,23 个零读取字段的格子全部是拒绝。它们在四列里都没有读取方,不是「暂时没用」,而是「从未被任何目的需要」。这为下一步的删列提供了依据:删的不是数据,是一整行没有允许格子的字段。
矩阵还有一个副作用:它把「字段该不该存在」变成了「有没有一个格子允许它」。以前删字段要说服自己,现在只需要看那一行是不是全空;全空的行不需要争论,直接进删除清单。
四、停写、观察、删列:三步迁移
删列迁移分三步,每一步之间至少隔一次发布。第一步停写:把所有写入这些字段的代码路径摘掉,列保留、允许为空;第二步观察两周,看有没有隐藏的读取方冒出来;第三步才真正 DROP COLUMN。
回滚靠备份。数据库每天备份、保留 30 天,所以删列之后最坏的情况是回到某一天的副本,再重放增量;这也是为什么停写要先观察两周——两周足够覆盖月度报表和大部分低频脚本。
这次迁移涉及 3 张表:profiles 去掉营销类字段,events 去掉调试类字段,invitations 去掉历史别名列。另有 2 个报表需要改 SQL,1 个导出脚本要把 SELECT * 换成显式列名。三处改动都不大,但必须在删列之前完成。
3 张表的改动按依赖顺序排:先改 invitations 的别名列,再改 profiles 的营销字段,最后改 events 的调试字段。events 写入量最大,放在最后,出问题时最容易从备份里单独恢复。
停写期的两周不是等待,而是验证。他把 2 个报表和 1 个导出脚本各跑一遍,比对行数与关键字段;再在查询日志里搜这些列名,确认没有任何计划外的读取。两周结束仍然零读取,才进入删列。
两周的观察期也覆盖了一次月度报表。报表在每月 1 日生成,窗口太短就会错过它;14 天是按这张报表的月度周期定的,不是通用常数,换成季度报表就要相应拉长。
复算:把删除前后的字段数与矩阵格子对齐。
字段总数 78
零读取字段 9 + 8 + 6 = 23
删除比例 23 ÷ 78 = 29.5%
删后字段 78 − 23 = 55
矩阵总格数 78 × 4 = 312
允许格 96,96 ÷ 312 = 30.8%
拒绝格 312 − 96 = 216,216 ÷ 312 = 69.2%
删后矩阵 55 × 4 = 220
删后允许占比 96 ÷ 220 = 43.6%
删掉 23 个字段之后,矩阵从 312 格缩到 220 格,允许格仍然是 96 格,占比从 30.8% 升到 43.6%。分母变小、分子不变,说明被删掉的字段本来就没有任何允许格;如果删完之后允许占比没变,那说明删错了对象。
五、行动清单与复算验收
- 导出 6 个月的应用日志与查询日志,按字段名统计读取次数。
- 列出 23 个零读取字段,按营销 9、调试 8、历史遗留 6 分类。
- 给 78 个字段各标一个主目的,填完 312 格矩阵。
- 停写这 23 个字段,观察 2 周,期间不动表结构。
- 改完 3 张表、2 个报表、1 个导出脚本,再执行删列。
- 留一份回滚脚本,写清从哪天备份恢复、如何重放增量。
- 给每个保留字段写一句保留理由,指向具体的读取方。
- 每季度复查一次读取日志,新出现的零读取字段进下一批。
验收标准:78 个字段每一个都能指到一个具体读取方,23 个零读取字段全部完成停写、观察与删列,且矩阵中没有空白的格子。
八条里最容易被跳过的是第一条和第七条。没有读取日志,23 这个数字就是猜的;没有保留理由,删完之后新字段还会以同样的方式长回来。
删列上线那天,他盯着监控看了半小时,报表正常,导出正常,没有任何报警。省下的不是存储空间,而是下一次有人问「为什么收公司规模」时,他不用再编一个理由。
使用边界与实操验收
最小化不等于功能砍半。 删的是没人读的字段,不是用户看得见的功能;判断标准是读取路径,不是产品野心。
有些字段是法定义务。 发票相关的财务字段要按法定年限保留,不能因为「没人读」就删;这类字段在矩阵里单独标注依据,不参与零读取清理。
删除有迁移风险。 删列不可逆,SELECT *、视图、外部报表和定时任务都可能隐式依赖;停写两周与备份 30 天是底线,不是可选项。
报表可能间接依赖。 报表 SQL 里没写列名,不代表没用到;聚合、分组和导出模板都可能间接引用,必须逐个跑一遍再删。
「以后可能有用」不是目的。 目的必须是当下某个具体功能或法定义务;说不出现在谁在读,就按零读取处理,等真的需要时再重新收集。
关键参考与核验范围
- GDPR Art 5 :用于核对目的限定、数据最小化与存储限制的原则。
- GDPR Art 6 :用于核对六类合法性依据与目的的关系。
- ICO 合法性依据 :用于核对「目的—依据」配对的操作说明。
- NIST Privacy Framework :用于核对数据最小化在隐私工程中的位置。
- OWASP Top 10 Privacy Risks :用于核对过度收集的风险描述。
以上链接于 2026-10-26 实测可公开访问;未核验版本、价格与配额。核验日期:2026-10-26。
上述文档只用于核对概念与条款编号;78 个字段、23 个零读取字段、312 格矩阵与全部比例均取自本组教学基线,与文档内容无对应关系。法律表述以适用法域与专业意见为准。
系列导航
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。