用户说「时间字段错了」,但真正的坑藏在 WHERE 枚举里
排查一个数据统计口径不一致的 bug,用户说得斩钉截铁:「应该是按首单时间匹配的,结果它用了入会时间,改过来就好了。」我差点就直接去改时间字段。
幸好没有。
现象
某后台两个报表页面的同一个用户指标出现了严重分歧:A 页面显示 4,B 页面显示 79。按业务逻辑,两个页面的口径应当一致。用户判断:"估计是 A 页面的 SQL 里用了入会时间,而不是首单时间,改成首单时间就能对齐。"
根因
SSH 进服务器,找到 A 页面对应的接口实现,把 SQL 完整抄出来逐行看。时间字段用的是 first_shop_time——即首单时间,和用户期望的一模一样,本来就没错。
继续二分:把 A 和 B 两个接口的 SQL 并排对比,逐个 WHERE 条件开关测试。差异点出现了:
-- A 页面(数据只有 4 条)
AND b.channel = 'POS'
-- B 页面(数据 79 条)
-- 无 channel 过滤A 页面把渠道硬编码死锁成了 'POS' 一个字面值,而实际上绝大多数用户来自另一个渠道(PPMiniProgram),占比约 95%。这行过滤把绝大部分数据全部砍掉了,导致只剩 4 条。
用户描述的现象是事实,描述的根因是假设。两者必须分开对待。
这次如果照用户说的去改时间字段,会发现字段本来就是 first_shop_time,改完数字纹丝不动,然后还要再开一轮排查——等于白白浪费一个完整的修复周期,还会让用户对你的判断力产生怀疑。
几类高频误判:
- 「时间字段错了」→ 通常时间字段是对的,过滤条件才是错的
- 「应该按 X 维度匹配」→ 维度对,但 X 的枚举值不全
- 「肯定是缓存没刷」→ 代码本身没改对,缓存只是放大器
正解
接到「数据不对」类 bug,标准流程是:
第一步,把现象和假设分开列出:
现象:A 页面显示 4,B 页面显示 79,口径应一致。
用户假设:时间字段用错了(待验证,不能当事实)。
第二步,SSH 读真实 SQL:
不凭印象,把接口对应的函数和 SQL 完整抄出来。对比两个接口的 WHERE 条件逐项差异。
第三步,DB 里跑二分:
移除 / 添加每个 WHERE 条件,看数字如何变化,定位到确切的差异行。
第四步,对比用户假设和实测根因,再决定改什么:
- 一致 → 用户假设对,顺着改;
- 不一致 → 回话告知「实测根因是 X,与您判断的 Y 不同,建议改 X」,让用户裁决,而不是悄悄按自己的结论动手。
本案修复就一行:把 AND b.channel = 'POS' 换成包含所有合法渠道的条件,或者删除不合理的字面值过滤。
在 spec 或修复 PR 里固化三分结构:
## 调查发现(实地验证)
**关键澄清:用户假设的「时间字段错误」并非根因。**
实际根因:channel 过滤使用了字面值 'POS',遗漏其他渠道数据(占 95%)。
| 实测项 | 结果 |
|---|---|
| A 页面 SQL 时间字段 | first_shop_time(正确) |
| A/B 差异点 | AND b.channel='POS' 仅在 A 存在 |
| 移除该条件后 A 页面数据 | 与 B 对齐(79 条) |这份记录让 reviewer 和用户都能看到根因验证路径,不会把下一轮 bug 再归到时间字段上。
一句话外卖
用户给的根因是假设,不是 spec;只有你自己 SSH 跑出来的数字,才算 root cause。