0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

為什么在語義相同的情況下group by和distinct效率相同呢?

jf_ro2CN3Fa ? 來源:CSDN ? 2023-01-09 10:46 ? 次閱讀

結(jié)論

先說大致的結(jié)論:

在語義相同,有索引的情況下:group by和distinct都能使用索引,效率相同。

在語義相同,無索引的情況下:distinct效率高于group by。原因是distinct 和 group by都會(huì)進(jìn)行分組操作,但group by可能會(huì)進(jìn)行排序,觸發(fā)filesort,導(dǎo)致sql執(zhí)行效率低下。

基于這個(gè)結(jié)論,你可能會(huì)問:

為什么在語義相同,有索引的情況下,group by和distinct效率相同?

在什么情況下,group by會(huì)進(jìn)行排序操作?

帶著這兩個(gè)問題找答案。接下來,我們先來看一下distinct和group by的基礎(chǔ)使用。

基于 Spring Boot + MyBatis Plus + Vue & Element 實(shí)現(xiàn)的后臺(tái)管理系統(tǒng) + 用戶小程序,支持 RBAC 動(dòng)態(tài)權(quán)限、多租戶、數(shù)據(jù)權(quán)限、工作流、三方登錄、支付、短信、商城等功能

distinct的使用

distinct用法

SELECTDISTINCTcolumnsFROMtable_nameWHEREwhere_conditions;

例如:

mysql>selectdistinctagefromstudent;
+------+
|age|
+------+
|10|
|12|
|11|
|NULL|
+------+
4rowsinset(0.01sec)

DISTINCT 關(guān)鍵詞用于返回唯一不同的值。放在查詢語句中的第一個(gè)字段前使用,且作用于主句所有列。

如果列具有NULL值,并且對(duì)該列使用DISTINCT子句,MySQL將保留一個(gè)NULL值,并刪除其它的NULL值,因?yàn)镈ISTINCT子句將所有NULL值視為相同的值。

distinct多列去重

distinct多列的去重,則是根據(jù)指定的去重的列信息來進(jìn)行,即只有所有指定的列信息都相同,才會(huì)被認(rèn)為是重復(fù)的信息。

SELECTDISTINCTcolumn1,column2FROMtable_nameWHEREwhere_conditions;
mysql>selectdistinctsex,agefromstudent;
+--------+------+
|sex|age|
+--------+------+
|male|10|
|female|12|
|male|11|
|male|NULL|
|female|11|
+--------+------+
5rowsinset(0.02sec)

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 實(shí)現(xiàn)的后臺(tái)管理系統(tǒng) + 用戶小程序,支持 RBAC 動(dòng)態(tài)權(quán)限、多租戶、數(shù)據(jù)權(quán)限、工作流、三方登錄、支付、短信、商城等功能

group by的使用

對(duì)于基礎(chǔ)去重來說,group by的使用和distinct類似:

單列去重

語法:

SELECTcolumnsFROMtable_nameWHEREwhere_conditionsGROUPBYcolumns;

執(zhí)行:

mysql>selectagefromstudentgroupbyage;
+------+
|age|
+------+
|10|
|12|
|11|
|NULL|
+------+
4rowsinset(0.02sec)

多列去重

語法:

SELECTcolumnsFROMtable_nameWHEREwhere_conditionsGROUPBYcolumns;

執(zhí)行:

mysql>selectsex,agefromstudentgroupbysex,age;
+--------+------+
|sex|age|
+--------+------+
|male|10|
|female|12|
|male|11|
|male|NULL|
|female|11|
+--------+------+
5rowsinset(0.03sec)

區(qū)別示例

兩者的語法區(qū)別在于,group by可以進(jìn)行單列去重,group by的原理是先對(duì)結(jié)果進(jìn)行分組排序,然后返回每組中的第一條數(shù)據(jù)。且是根據(jù)group by的后接字段進(jìn)行去重的。

例如:

mysql>selectsex,agefromstudentgroupbysex;
+--------+-----+
|sex|age|
+--------+-----+
|male|10|
|female|12|
+--------+-----+
2rowsinset(0.03sec)

distinct和group by原理

在大多數(shù)例子中,DISTINCT可以被看作是特殊的GROUP BY,它們的實(shí)現(xiàn)都基于分組操作,且都可以通過松散索引掃描、緊湊索引掃描(關(guān)于索引掃描的內(nèi)容會(huì)在其他文章中詳細(xì)介紹,就不在此細(xì)致介紹了)來實(shí)現(xiàn)。

DISTINCT和GROUP BY都是可以使用索引進(jìn)行掃描搜索的。例如以下兩條sql(只單單看表格最后extra的內(nèi)容),我們對(duì)這兩條sql進(jìn)行分析,可以看到,在extra中,這兩條sql都使用了緊湊索引掃描Using index for group-by。

所以,在一般情況下,對(duì)于相同語義的DISTINCT和GROUP BY語句,我們可以對(duì)其使用相同的索引優(yōu)化手段來進(jìn)行優(yōu)化。

mysql>explainselectint1_indexfromtest_distinct_groupbygroupbyint1_index;
+----+-------------+-----------------------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+
|id|select_type|table|partitions|type|possible_keys|key|key_len|ref|rows|filtered|Extra|
+----+-------------+-----------------------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+
|1|SIMPLE|test_distinct_groupby|NULL|range|index_1|index_1|5|NULL|955|100.00|Usingindexforgroup-by|
+----+-------------+-----------------------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+
1rowinset(0.05sec)

mysql>explainselectdistinctint1_indexfromtest_distinct_groupby;
+----+-------------+-----------------------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+
|id|select_type|table|partitions|type|possible_keys|key|key_len|ref|rows|filtered|Extra|
+----+-------------+-----------------------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+
|1|SIMPLE|test_distinct_groupby|NULL|range|index_1|index_1|5|NULL|955|100.00|Usingindexforgroup-by|
+----+-------------+-----------------------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+
1rowinset(0.05sec)

但對(duì)于GROUP BY來說,在MYSQL8.0之前,GROUP Y默認(rèn)會(huì)依據(jù)字段進(jìn)行隱式排序。

可以看到,下面這條sql語句在使用了臨時(shí)表的同時(shí),還進(jìn)行了filesort。

mysql>explainselectint6_bigger_randomfromtest_distinct_groupbyGROUPBYint6_bigger_random;
+----+-------------+-----------------------+------------+------+---------------+------+---------+------+-------+----------+---------------------------------+
|id|select_type|table|partitions|type|possible_keys|key|key_len|ref|rows|filtered|Extra|
+----+-------------+-----------------------+------------+------+---------------+------+---------+------+-------+----------+---------------------------------+
|1|SIMPLE|test_distinct_groupby|NULL|ALL|NULL|NULL|NULL|NULL|97402|100.00|Usingtemporary;Usingfilesort|
+----+-------------+-----------------------+------------+------+---------------+------+---------+------+-------+----------+---------------------------------+
1rowinset(0.04sec)

隱式排序

對(duì)于隱式排序,我們可以參考Mysql官方的解釋

大致解釋一下:

GROUP BY 默認(rèn)隱式排序(指在 GROUP BY 列沒有 ASC 或 DESC 指示符的情況下也會(huì)進(jìn)行排序)。然而,GROUP BY進(jìn)行顯式或隱式排序已經(jīng)過時(shí)(deprecated)了,要生成給定的排序順序,請(qǐng)?zhí)峁?ORDER BY 子句。

所以,在Mysql8.0之前,Group by會(huì)默認(rèn)根據(jù)作用字段(Group by的后接字段)對(duì)結(jié)果進(jìn)行排序。在能利用索引的情況下,Group by不需要額外進(jìn)行排序操作;但當(dāng)無法利用索引排序時(shí),Mysql優(yōu)化器就不得不選擇通過使用臨時(shí)表然后再排序的方式來實(shí)現(xiàn)GROUP BY了。

且當(dāng)結(jié)果集的大小超出系統(tǒng)設(shè)置臨時(shí)表大小時(shí),Mysql會(huì)將臨時(shí)表數(shù)據(jù)copy到磁盤上面再進(jìn)行操作,語句的執(zhí)行效率會(huì)變得極低。這也是Mysql選擇將此操作(隱式排序)棄用的原因。

基于上述原因,Mysql在8.0時(shí),對(duì)此進(jìn)行了優(yōu)化更新:

大致解釋一下:

從前(Mysql5.7版本之前),Group by會(huì)根據(jù)確定的條件進(jìn)行隱式排序。在mysql 8.0中,已經(jīng)移除了這個(gè)功能,所以不再需要通過添加order by null 來禁止隱式排序了,但是,查詢結(jié)果可能與以前的 MySQL 版本不同。要生成給定順序的結(jié)果,請(qǐng)按通過ORDER BY指定需要進(jìn)行排序的字段。

因此,我們的結(jié)論也出來了:

在語義相同,有索引的情況下:

group by和distinct都能使用索引,效率相同。因?yàn)間roup by和distinct近乎等價(jià),distinct可以被看做是特殊的group by。

在語義相同,無索引的情況下:

distinct效率高于group by。原因是distinct 和 group by都會(huì)進(jìn)行分組操作,但group by在Mysql8.0之前會(huì)進(jìn)行隱式排序,導(dǎo)致觸發(fā)filesort,sql執(zhí)行效率低下。

但從Mysql8.0開始,Mysql就刪除了隱式排序,所以,此時(shí)在語義相同,無索引的情況下,group by和distinct的執(zhí)行效率也是近乎等價(jià)的。

推薦group by的原因

group by語義更為清晰

group by可對(duì)數(shù)據(jù)進(jìn)行更為復(fù)雜的一些處理

相比于distinct來說,group by的語義明確。且由于distinct關(guān)鍵字會(huì)對(duì)所有字段生效,在進(jìn)行復(fù)合業(yè)務(wù)處理時(shí),group by的使用靈活性更高,group by能根據(jù)分組情況,對(duì)數(shù)據(jù)進(jìn)行更為復(fù)雜的處理,例如通過having對(duì)數(shù)據(jù)進(jìn)行過濾,或通過聚合函數(shù)對(duì)數(shù)據(jù)進(jìn)行運(yùn)算。






審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • MySQL
    +關(guān)注

    關(guān)注

    1

    文章

    789

    瀏覽量

    26298
  • null
    +關(guān)注

    關(guān)注

    0

    文章

    17

    瀏覽量

    3894

原文標(biāo)題:面試官:MySQL中的 distinct 和 group by 哪個(gè)效率更高?

文章出處:【微信號(hào):芋道源碼,微信公眾號(hào):芋道源碼】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    運(yùn)放使用時(shí),虛短,虛斷什么情況下使用?

    運(yùn)放使用時(shí),虛短,虛斷什么情況下使用?是單端,差分輸入條件都能使用么?
    發(fā)表于 09-14 08:53

    條件相同情況下,stm8L與STM32L誰的功耗會(huì)更低?

    stm8L與STM32L誰的功耗會(huì)更低,條件相同情況下,正常運(yùn)行和低功耗模式時(shí)。
    發(fā)表于 04-16 07:17

    GD32斷上電采樣相同電壓有偏差如何處理?

    大家是否碰到過使用GD32 MCU斷上電采樣相同的電壓存在偏差的情況?如果在上電正常運(yùn)行的情況下,采樣相同的直流電壓,ADC采樣數(shù)值都比較穩(wěn)定,而斷上電重新運(yùn)行的時(shí)候采樣
    的頭像 發(fā)表于 02-29 09:44 ?670次閱讀
    GD32斷上電采樣<b class='flag-5'>相同</b>電壓有偏差如何處理?

    什么情況下電容器會(huì)被擊穿

    電容器是一種常見的電子元件,廣泛應(yīng)用于各個(gè)領(lǐng)域。然而,特定條件,電容器可能會(huì)發(fā)生擊穿現(xiàn)象,導(dǎo)致其無法正常工作甚至損壞。那么,什么情況下電容器會(huì)被擊穿
    的頭像 發(fā)表于 02-19 14:11 ?1953次閱讀

    溫度很低的情況下,電機(jī)效率會(huì)降低嗎?

    溫度很低的情況下,電機(jī)效率會(huì)降低嗎? 電機(jī)工業(yè)和家庭中廣泛應(yīng)用,其效率是評(píng)估其性能的重要指標(biāo)之一。然而,溫度是影響電機(jī)效率的關(guān)鍵因素之一。
    的頭像 發(fā)表于 01-04 11:26 ?1353次閱讀

    ADE7880設(shè)置ADE_CF1DEN采用不同的數(shù)據(jù)時(shí),相同的負(fù)載情況下為什么CF1輸出的脈沖間隔相同

    ADE_CF1DEN采用不同的數(shù)據(jù)時(shí)(如上述的0X0080和0X1000),相同的負(fù)載情況下,為什么CF1輸出的脈沖間隔相同,都是23秒?
    發(fā)表于 12-26 06:45

    變頻器頻率相同能否使異步電機(jī)轉(zhuǎn)速不同?

    變頻器頻率相同能否使異步電機(jī)轉(zhuǎn)速不同?還有用1臺(tái)變頻器控制2臺(tái)異步電機(jī),頻率相同情況下,能否使兩臺(tái)異步電機(jī)轉(zhuǎn)速不同?
    發(fā)表于 12-21 06:21

    干式電容器什么情況下會(huì)爆炸?

    干式電容器是一種常見的電子元件,但在特定情況下可能會(huì)發(fā)生爆炸。那么,干式電容器在哪些情況下會(huì)發(fā)生爆炸?
    的頭像 發(fā)表于 12-15 14:20 ?593次閱讀

    什么是always on buffer?什么情況下需要插always on buffer?

    相比普通的buffer cell,always on buffer(AOB)有secondary always on pin,可以讓AOB即使primary power off的情況下保持on的狀態(tài);AOBsecondary
    的頭像 發(fā)表于 12-01 15:31 ?1898次閱讀
    什么是always on buffer?什么<b class='flag-5'>情況下</b>需要插always on buffer?

    電源適配器什么情況下容易效率低下?

    電源適配器什么情況下容易效率低下? 電源適配器作為電子設(shè)備中不可或缺的一部分,負(fù)責(zé)將交流電轉(zhuǎn)換為直流電,為電子設(shè)備提供穩(wěn)定的電源。然而,日常使用中,我們可能會(huì)遇到電源適配器
    的頭像 發(fā)表于 11-23 16:03 ?949次閱讀

    變頻工作的情況下,諸曲線又是怎么變化的?

    想問變頻工作的情況下,諸曲線又是怎么變化的? 此問題困擾已久,希望大家給出分析過程,謝謝!??! 如果能寫出V/f和VC的區(qū)別,就真的能夠用到工程實(shí)踐里啦。
    發(fā)表于 11-21 08:14

    電機(jī)什么情況下需要選擇圓柱滾子軸承?

    電機(jī)什么情況下需要選擇圓柱滾子軸承? 圓柱滾子軸承是一種常用的電機(jī)配件,可以提供高負(fù)荷能力和高速旋轉(zhuǎn)的特性。以下情況下,電機(jī)需要選擇圓柱滾子軸承。 第一,高負(fù)荷
    的頭像 發(fā)表于 11-06 11:50 ?1047次閱讀

    電容器不放電的情況下為什么不能長(zhǎng)期儲(chǔ)存電能?

    電容器不放電的情況下為什么不能長(zhǎng)期儲(chǔ)存電能? 電容器被廣泛應(yīng)用在電子電路中,是一種能夠儲(chǔ)存電荷的裝置。雖然電容器可以儲(chǔ)存電荷,但是不放電的情況
    的頭像 發(fā)表于 10-26 11:16 ?1426次閱讀

    相同封裝規(guī)格的共模電感線圈電性能是否相同

    電子發(fā)燒友網(wǎng)站提供《相同封裝規(guī)格的共模電感線圈電性能是否相同.docx》資料免費(fèi)下載
    發(fā)表于 10-15 11:04 ?0次下載

    鐵氧體磁環(huán)電感封裝相同電流大小相同

    的鐵氧體磁環(huán)電感的電性能是一樣的嗎?今天我們就來簡(jiǎn)單討論一這個(gè)問題。 大家對(duì)于鐵氧體磁環(huán)電感的了解確實(shí)是存在很多不足的,無論是應(yīng)用方面,還是選型方面。鐵氧體磁環(huán)電感的規(guī)格型號(hào)有很多,大部分情況下的選型都是選擇某一個(gè)規(guī)格
    的頭像 發(fā)表于 10-07 12:49 ?458次閱讀