1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        京東一面:MySQL 中的 distinct 和 group by 哪個效率更高?太刁鉆了吧!

        共 10154字,需瀏覽 21分鐘

         ·

        2023-03-07 23:56

        點(diǎn)擊關(guān)注公眾號,Java干貨及時送達(dá)

        先說大致的結(jié)論(完整結(jié)論在文末):

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

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

        • 為什么在語義相同,有索引的情況下,group bydistinct效率相同?
        • 在什么情況下,group by會進(jìn)行排序操作?

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

        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關(guān)鍵詞用于返回唯一不同的值。放在查詢語句中的第一個字段前使用,且作用于主句所有列。

        如果列具有 NULL 值,并且對該列使用DISTINCT子句,MySQL 將保留一個 NULL 值,并刪除其它的 NULL 值,因為DISTINCT子句將所有 NULL 值視為相同的值。

        distinct 多列去重

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

        SELECT DISTINCT column1,column2 FROM table_name WHERE where_conditions;
        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 的使用

        對于基礎(chǔ)去重來說,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可以進(jìn)行單列去重,group by的原理是先對結(jié)果進(jìn)行分組排序,然后返回每組中的第一條數(shù)據(jù)。且是根據(jù)group by的后接字段進(jìn)行去重的。

        例如:

        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)都基于分組操作,且都可以通過松散索引掃描、緊湊索引掃描(關(guān)于索引掃描的內(nèi)容會在其他文章中詳細(xì)介紹,就不在此細(xì)致介紹了)來實現(xiàn)。

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

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

        mysql> explain select int1_index from test_distinct_groupby group by int1_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 | Using index for group-by |
        +----+-------------+-----------------------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+
        1 row in set (0.05 sec)

        mysql> explain select distinct int1_index from test_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 | Using index for group-by |
        +----+-------------+-----------------------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+
        1 row in set (0.05 sec)

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

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

        mysql> explain select int6_bigger_random from test_distinct_groupby GROUP BY int6_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 | Using temporary; Using filesort |
        +----+-------------+-----------------------+------------+------+---------------+------+---------+------+-------+----------+---------------------------------+
        1 row in set (0.04 sec)

        隱式排序

        對于隱式排序,我們可以參考 MySQL 官方的解釋:

        https://dev.mysql.com/doc/refman/5.7/en/order-by-optimization.html

        GROUP BY implicitly sorts by default (that is, in the absence of ASC or DESC designators for GROUP BY columns). However, relying on implicit GROUP BY sorting (that is, sorting in the absence of ASC or DESC designators) or explicit sorting for GROUP BY (that is, by using explicit ASC or DESC designators for GROUP BY columns) is deprecated. To produce a given sort order, provide an ORDER BY clause.

        大致解釋一下:

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

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

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

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

        https://dev.mysql.com/doc/refman/8.0/en/order-by-optimization.html

        Previously (MySQL 5.7 and lower), GROUP BY sorted implicitly under certain conditions. In MySQL 8.0, that no longer occurs, so specifying ORDER BY NULL at the end to suppress implicit sorting (as was done previously) is no longer necessary. However, query results may differ from previous MySQL versions. To produce a given sort order, provide an ORDER BY clause.

        大致解釋一下:

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

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

        • 在語義相同,有索引的情況下:group bydistinct都能使用索引,效率相同。因為group bydistinct近乎等價,distinct 可以被看做是特殊的group by
        • 在語義相同,無索引的情況下:distinct效率高于group by。原因是distinctgroup by都會進(jìn)行分組操作,但group by在 MySQL8.0 之前會進(jìn)行隱式排序,導(dǎo)致觸發(fā) filesort,sql 執(zhí)行效率低下。但從 MySQL8.0 開始,MySQL 就刪除了隱式排序,所以,此時在語義相同,無索引的情況下,group bydistinct的執(zhí)行效率也是近乎等價的。

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

        原文:https://sourl.cn/H8iFRE

          

        1、社區(qū)糾紛不斷:程序員何苦為難程序員?

        2、該死的單元測試,寫起來到底有多痛?

        3、互聯(lián)網(wǎng)人為什么學(xué)不會擺爛

        4、為什么國外JetBrains做 IDE 就可以養(yǎng)活自己,國內(nèi)不行?區(qū)別在哪?

        5、相比高人氣的Rust、Go,為何 Java、C 在工具層面進(jìn)展緩慢?

        6、讓程序員早點(diǎn)下班的《技術(shù)寫作指南》

        點(diǎn)

        點(diǎn)

        點(diǎn)點(diǎn)

        點(diǎn)在看

        瀏覽 41
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            日韩九九九| ass众多明星裸体pics | 男女黄色大片操逼网站 | 亚洲第一综合 | 国产三级久久久久 | 雷电将军安慰部下模拟器苹果破解版 | 猛男 大 粗 猛 爽h男人味69XX | 亚洲日本在线播放 | 欧美a大片 | 韩国伦理大胸 |