通常,我們要統計一個字段有幾種值有兩種方法:在語句中使用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秒
以上測試表明,我們得出的結論是正確的,實際應用中要使用哪個,還得根據實際情況來決定。