在數據庫操作中,我們常常遇到需要將數據去重計數的工作。例如:
表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需要將col列中的全部內容都存儲在一個內存中,可以理解為一個hash結構,key為col的值,最后計算hash結構中有多少個key即可得到結果。
很明顯,需要將所有不同的值都存起來。內存消耗可能較大。
而group by的方式是先將col排序。而數據庫中的group一般使用sort的方法,即數據庫會先對col進行排序。而排序的基本理論是,時間復雜為nlogn,空間為1.,然后只要單純的計數就可以了。優點是空間復雜度小,缺點是要進行一次排序,執行時間會較長。
兩中方法各有優劣,在使用的時候,我們需要根據實際情況進行取舍。
具體情況可參考如下法則
數據分布 | 去重方式 | 原因 |
離散 | group | distinct空間占用較大,在時間復雜度允許的情況下,group 可以發揮空間復雜度優勢 |
集中 | distinct | distinct空間占用較小,可以發揮時間復雜度優勢 |
兩個極端:
1.數據列的所有數據都一樣,即去重計數的結果為1時,用distinct最佳
2.如果數據列唯一,沒有相同數值,用group 最好
當然,在group by時,某些數據庫產品會根據數據列的情況智能地選擇是使用排序去重還是hash去重,例如postgresql。當然,我們可以根據實際情況對執行計划進行人工的干預,而這不是這里要討論的話題了。