最近在做报表统计的时候碰到一个诡异的bug,union左边查出来有4条数据,右边是0条,理论上最后的结果有4条,但是执行结果很意外,只有三条。最后的解决办法是在查询数据列加上了各自的报表时间。
原始sql:
改正后:
union在做一些数据合并统计的时候很有用,但稍不注意就会踩坑导致数据丢失统计出错。
使用union时一定要注意union自带了去重功能,而且机制类似于 把左右两边的数据完全做完合并再来一个distinct,所以一旦有两行的数据一模一样时,union会去掉这些重复行,即使这些重复行只是存在于其中一个结果集的 。
union all的机制类似于把左右两边的数据完全做完合并,并且不会做去重。虽然可以使用union all就不会做去重,但是试想一下这个需求:如果我们需要把左结果集和右结果集的数据做合并,但是左结果集和右结果集存在一些重复,这种重复数据是应该去掉的,而左结果集和右结果集自身存在的重复行是应该保留的,因为我们的目的并不是在每个结果集做去重,而是保证union的左边数据不和右边数据重复。建议认真考虑使用场景再决定是否使用union all。
union去重时去掉的重复数据如果是我们需要保留的,因为他们并不是来自于同一行,只是因为值完全一致而被去掉了,那么应该把这些数据的唯一标志也放在查询列,这样就不是重复数据了。
备注:考虑信息敏感性,以下分析场景测试环境模拟,相关数据做以下说明
发现了一些端倪,在mysql-bin.000004中有对该表的2次truncate *** 作,等等,好像发现了什么,那条丢失的数据也是在这个mysql-bin.000004文件中,梳理下逻辑,难道那条记录在2次truncate之间,于是单独对这个binlog做详细解析,得到以下信息
到此基本了解了这条记录为何会诡异丢失了 ,与客户确认跑批灌数据的逻辑,了解到会对该表做truncate,但由于 误 *** 作 ,在跑批开始后,又触发了一轮truncate行为,导致已经插入到该表的部分数据再次被清理了,也就导致了在解析binlog时部分记录丢失了,但并未观测到有删除的行为,而是被truncate方式清理.
备注 :虽然binlog记录的信息足够多,但当故障原因定位后,由于其并未记录 对该 *** 作的IP及用户 信息,如果不开审计,也只能知道发生了该行为,但无法具体定位触发该行为的"人".
all_student表是所有的学生信息,fail_student表是不及格的学生信息
select * from all_student
select * from fail_student
查询及格的学生信息
select * from all_student
where name not in (
select name from fail_student
)
假如fail_student有一条name为null的记录
再次查询及格的学生信息,结果集为空
select * from all_student
where name not in (
select name from fail_student
)
解决方案
1.修改表结构,设置name字段为not null,并设置默认值
2.修改sql为
select * from all_student a
left join fail_student f on a.name = f.name
where f.name is null
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)