关于查询数据去重

开始

MySQL中,去除重复数据的方式有两种:分别是DISTINCTGROUP BY,虽然两者的去重效率都不高,但是GROUP BY的执行效率要比DISTINCT高,有图为证:
图样,并没有图,这里只把道理说清楚,图不重要。


GROUP BY

使用GROUP BY去重,是直接把每一行记录分到对应的组里,第一条入组的记录会成为组代表,SELECT字段值就是选取该条记录的字段值。


DISTINCT

而使用DISTINCT去重,是真正意义上的去重,对于每一条记录,都会先查询一下是否已经存在(慢在这里),不存在就选上,存在就跳过。


索引

如果对需要去重的关键字段加上索引,去重效率会有大幅度提升,而且使用DISTINCT去重的执行效率,和使用GROUP BY去重的差不多。
其实索引就像是GROUP BY的缓存,对于关键字段的相同的记录,它们的索引是一样的,就像是分到了同一组里。有了索引,就好像已经分好了组,去重的速度自然就变快了;而DISTINCT会按照GROUP BY的方式去重,彼此的效率自然也就差不多了。


子查询

讨论数据去重问题怎么会扯上子查询呢?我们先来探讨一下重复数据是怎么产生的。


JOIN + GROUP BY

一般来说,单表里面很少会有重复数据,但是连接(JOIN)上一对多关系或者多对多关系的其他表时,总的记录数量就有可能增加。
然而我们更关注主表的内容,总是希望主表的记录能保持唯一,副表的某些内容用GROUP_ CONCAT()串联起来作为一个字段值附在主表上就好了,这时我们通常会用GROUP BY(不用效率低的DISTINCT)主表的主键来去重。
主表的主键当然有索引,但是这个索引只能用在主表里面使用,JOIN上其他表后,索引就没什么用了(当然,),这时候再用GROUP BY,效率不但没有提高,还可能变得更低(因为记录数量增加了)。

解决数据重复问题,可以考虑如何去除重复,但更应该考虑的是:如何阻止重复数据的产生(问题的根源)


Subquery VS JOIN

普遍的,大家总是推崇使用JOIN,而避免使用子查询。因为大多情况下,JOIN可以替代子查询,并且效率更高。

反过来说,就是子查询也能替代JOIN

所以,子查询跟数据去重问题扯上了!
JOIN,特别是OUTER JOIN可能会产生数据重复,正是问题的根源。
如果不考虑去重,那么自然选择JOIN,而不用子查询;但是如果在JOIN后又要用GROUP BY去重,那么还不如选择子查询。合适地使用子查询,执行效率会比JOIN+GROUP BY要更高。


最后说一句

不要整天的JOINJOINJOIN
有的还整天LEFT JOINLEFT JOINLEFT JOIN……