MySQL 中的 distinct 和 group by 哪個效率更高?

先說大致的結論(完整結論在文末):
在語義相同,有索引的情況下group by和distinct都能使用索引,效率相同。
在語義相同,無索引的情況下:distinct效率高于group by。原因是distinct 和 group by都會進行分組操作,但group by可能會進行排序,觸發(fā)filesort,導致sql執(zhí)行效率低下。
?
基于這個結論,你可能會問:
??
為什么在語義相同,有索引的情況下,group by和distinct效率相同?
在什么情況下,group by會進行排序操作?
?
帶著這兩個問題找答案。接下來,我們先來看一下distinct和group by的基礎使用。
?
# distinct的使用
?
distinct用法
?
SELECT?DISTINCT columns FROM table_name WHERE where_conditions;
?
?
例如:
mysql> select distinct age from student;
+------+
| age ?|
+------+
| ??10 |
| ??12 |
| ??11 |
| NULL |
+------+
4 rows in set (0.01 sec)
?
DISTINCT 關鍵詞用于返回唯一不同的值。放在查詢語句中的第一個字段前使用,且作用于主句所有列。
?
如果列具有NULL值,并且對該列使用DISTINCT子句,MySQL將保留一個NULL值,并刪除其它的NULL值,因為DISTINCT子句將所有NULL值視為相同的值。
?
distinct多列去重
distinct多列的去重,則是根據(jù)指定的去重的列信息來進行,即只有所有指定的列信息都相同,才會被認為是重復的信息。
語法:
SELECT DISTINCT column1,column2 FROM table_name WHERE where_conditions;
?
?
執(zhí)行:
mysql> select distinct sex,age from student;
+--------+------+
| sex ???| age ?|
+--------+------+
| male ??| ??10 |
| female | ??12 |
| male ??| ??11 |
| male ??| NULL |
| female | ??11 |
+--------+------+
5 rows in set (0.02 sec)
?
# group by的使用
對于基礎去重來說,group by的使用和distinct類似:
單列去重
?
語法:
SELECT columns FROM table_name WHERE where_conditions GROUP BY columns;
?
執(zhí)行:
mysql> select age from student group by age;
+------+
| age ?|
+------+
| ??10 |
| ??12 |
| ??11 |
| NULL |
+------+
4 rows in set (0.02 sec)
?
多列去重
?
語法:
SELECT columns FROM table_name WHERE where_conditions GROUP BY columns;
?
執(zhí)行:
mysql> select sex,age from student group by sex,age;
+--------+------+
| sex ???| age ?|
+--------+------+
| male ??| ??10 |
| female | ??12 |
| male ??| ??11 |
| male ??| NULL |
| female | ??11 |
+--------+------+
5 rows in set (0.03 sec)
?
區(qū)別示例
兩者的語法區(qū)別在于,group by可以進行單列去重,group by的原理是先對結果進行分組排序,然后返回每組中的第一條數(shù)據(jù)。且是根據(jù)group by的后接字段進行去重的。
?
例如:
mysql> select sex,age from student group by sex;
+--------+-----+
| sex ???| age |
+--------+-----+
| male ??| ?10 |
| female | ?12 |
+--------+-----+
2 rows in set (0.03 sec)
?
# distinct和group by原理
?
在大多數(shù)例子中,DISTINCT可以被看作是特殊的GROUP BY,它們的實現(xiàn)都基于分組操作,且都可以通過松散索引掃描、緊湊索引掃描(關于索引掃描的內(nèi)容會在其他文章中詳細介紹,就不在此細致介紹了)來實現(xiàn)。
?
DISTINCT和GROUP BY都是可以使用索引進行掃描搜索的。例如以下兩條sql(只單單看表格最后extra的內(nèi)容),我們對這兩條sql進行分析,可以看到,在extra中,這兩條sql都使用了緊湊索引掃描Using index for group-by。
?
因此,我們的結論也出來了:
?
在語義相同,有索引的情況下:
group by和distinct都能使用索引,效率相同。因為group by和distinct近乎等價,distinct可以被看做是特殊的group by。
?
在語義相同,無索引的情況下:
?
distinct效率高于group by。原因是distinct 和 group by都會進行分組操作,但group by在Mysql8.0之前會進行隱式排序,導致觸發(fā)filesort,sql執(zhí)行效率低下。但從Mysql8.0開始,Mysql就刪除了隱式排序,所以,此時在語義相同,無索引的情況下,group by和distinct的執(zhí)行效率也是近乎等價的。
?
# 推薦group by的原因
?
? 1.group by語義更為清晰
? 2.group by可對數(shù)據(jù)進行更為復雜的一些處理
?
相比于distinct來說,group by的語義明確。且由于distinct關鍵字會對所有字段生效,在進行復合業(yè)務處理時,group by的使用靈活性更高,group by能根據(jù)分組情況,對數(shù)據(jù)進行更為復雜的處理,例如通過having對數(shù)據(jù)進行過濾,或通過聚合函數(shù)對數(shù)據(jù)進行運算。