开始
在MySQL中,去除重复数据的方式有两种:分别是DISTINCT
和GROUP 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
要更高。
最后说一句
不要整天的JOIN
、JOIN
、JOIN
;
有的还整天LEFT JOIN
、LEFT JOIN
、LEFT JOIN
……