MySQL中DISTINCT與GROUP BY計數原理分析

通常,我們要統計一個字段有幾種值有兩種方法:在語句中使用DISTINCT或者GROUP BY,配合count進行查詢。
例如:

SELECT count(DISTINCT col) FROM table;
SELECT count(1) FROM (SELECT 1 FROM table GROUP BY col) alias;

那麼這兩者的效率究竟如何呢?網上的答案可謂前篇一律,大多說GROUP BY更勝一籌!對此,DISTINCT表示不服,那我是不是白活了!

今天我們就來了解一下這兩者的實現原理,最後才能知道它們究竟有啥區別。
DISTINCT:這種方式會將全部內容存儲在一個hash結構裏,最後通過計算hash結構中key的個數即可得到結果,典型的以空間換取時間的方式。
GROUP BY:這種方式是先將字段排序(一般使用sort),然後進行計數,典型的以時間換取空間。

瞭解原理之後,我們可以得出,

數據越是離散,DISTINCT需要消耗的空間越大,效率也就越低,此時GROUP BY的空間優勢就顯現了;相反,數據越是集中,DISTINCT空間佔用變小,時間優勢就顯現出來了。

但是,空口無憑,我們需要動手證明。
第一步,創建一張測試表:

CREATE TABLE `comments` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
    `uid` int(10) unsigned NOT NULL COMMENT '用戶uid',
    `aid` int(8) NOT NULL COMMENT '文章aid',  
    `content` text CHARACTER SET utf8mb4 NOT NULL COMMENT '發表內容',
    `picture` varchar(255) NOT NULL DEFAULT '' COMMENT '圖片', 
    `status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '顯示狀態 0:不顯示 1:顯示',
    `qid` int(10) NOT NULL DEFAULT '0' COMMENT '引用id',  
    `praise_num` int(10) NOT NULL DEFAULT '0' COMMENT '被贊數',
    `floor_num` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '樓層',
    `ip` int(10) NOT NULL COMMENT 'ip地址',
    `update_time` int(10) unsigned NOT NULL COMMENT '發表時間',
    `create_time` int(10) unsigned NOT NULL COMMENT '發表時間',
    PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

第二步,寫入500萬條記錄
一些測試的關鍵字段總數如下:
在這裏插入圖片描述
第三步,對上面的四個字段分別進行測試:
status字段

A: SELECT count(DISTINCT status) FROM comments;
B: SELECT count(1) FROM (SELECT 1 FROM comments GROUP BY status) alias;

分別執行100次,A語句的平均耗時爲0.882秒,B語句的平均耗時爲1.257秒

praise_num字段

A: SELECT count(DISTINCT praise_num) FROM comments;
B: SELECT count(1) FROM (SELECT 1 FROM comments GROUP BY praise_num) alias;

分別執行100次,A語句的平均耗時爲1.589秒,B語句的平均耗時爲1.848秒

floor_num字段

A: SELECT count(DISTINCT floor_num) FROM comments;
B: SELECT count(1) FROM (SELECT 1 FROM comments GROUP BY floor_num) alias;

分別執行100次,A語句的平均耗時爲1.840秒,B語句的平均耗時爲1.811秒

uid字段

A: SELECT count(DISTINCT uid) FROM comments;
B: SELECT count(1) FROM (SELECT 1 FROM comments GROUP BY uid) alias;

分別執行100次,A語句的平均耗時爲3.003秒,B語句的平均耗時爲1.927秒

以上測試表明,我們得出的結論是正確的,實際應用中要使用哪個,還得根據實際情況來決定。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章