在数据库操作中,我们常常遇到需要将数据去重计数的工作。例如:
表A,列col
A
C
A
B
C
D
A
B
结果就是一共出现4个不同的字母A、B、C、D
即结果为4
大体上我们可以选择count(distinct col)
的方法和group+count
的方法。
分别为:
select count(distinct col) from A;
select count(1) from (select 1 from A group by col) alias;
两中方法实现有什么不同呢?
其实上述两中方法分别是在运算和存储上的权衡。
distinct
distinct
需要将col列
中的全部内容都存储在一个内存中,可以理解为一个hash
结构,key
为col
的
值,最后计算hash
结构中有多少个key
即可得到结果。
很明显,需要将所有不同的值都存起来。内存消耗可能较大。
group by
而group by
的方式是先将col
排序。而数据库中的group
一般使用sort
的方法,即数据库会先对col
进
行排序。而排序的基本理论是,时间复杂为nlogn
,空间为1.,然后只要单纯的计数就可以了。优点是
空间复杂度小,缺点是要进行一次排序,执行时间会较长。
如果该我们仅仅想去重,而不需要排序,可以在后面加入order by null
子句后,MySQL不会创建
sort index
进行排序(内存排序非常快,优化效果并不明显,并且这个阶段只是每个数据块的排序)。
总结
两中方法各有优劣,在使用的时候,我们需要根据实际情况进行取舍。
具体情况可参考如下法则:
两个极端:
-
数据列的所有数据都一样,即去重计数的结果为1时,用
distinct
最佳。 -
如果数据列唯一,没有相同数值,用
group
最好。
当然,在group by
时,某些数据库产品会根据数据列的情况智能地选择是使用排序去重还是hash
去
重,例如postgresql
。当然,我们可以根据实际情况对执行计划进行人工的干预,而这不是这里要讨论
的话题了。