最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

MySQL中distinct語句的基本原理及其與group by的比較

 更新時(shí)間:2016年01月13日 15:06:14   作者:海底蒼鷹  
這篇文章主要介紹了MySQL中distinct語句的基本原理及其與group by的比較,一般情況下來說group by和distinct的實(shí)現(xiàn)原理相近且性能稍好,需要的朋友可以參考下

DISTINCT 實(shí)際上和 GROUP BY 操作的實(shí)現(xiàn)非常相似,只不過是在 GROUP BY 之后的每組中只取出一條記錄而已。所以,DISTINCT 的實(shí)現(xiàn)和 GROUP BY 的實(shí)現(xiàn)也基本差不多,沒有太大的區(qū)別。同樣可以通過松散索引掃描或者是緊湊索引掃描來實(shí)現(xiàn),當(dāng)然,在無法僅僅使用索引即能完成 DISTINCT 的時(shí)候,MySQL 只能通過臨時(shí)表來完成。但是,和 GROUP BY 有一點(diǎn)差別的是,DISTINCT 并不需要進(jìn)行排序。也就是說,在僅僅只是 DISTINCT 操作的 Query 如果無法僅僅利用索引完成操作的時(shí)候,MySQL 會利用臨時(shí)表來做一次數(shù)據(jù)的“緩存”,但是不會對臨時(shí)表中的數(shù)據(jù)進(jìn)行 filesort 操作。當(dāng)然,如果我們在進(jìn)行 DISTINCT 的時(shí)候還使用了 GROUP BY 并進(jìn)行了分組,并使用了類似于 MAX 之類的聚合函數(shù)操作,就無法避免 filesort 了。

下面我們就通過幾個(gè)簡單的 Query 示例來展示一下 DISTINCT 的實(shí)現(xiàn)。

1.首先看看通過松散索引掃描完成 DISTINCT 的操作:

sky@localhost : example 11:03:41> EXPLAIN SELECT DISTINCT group_id 
  -> FROM group_messageG
*************************** 1. row ***************************
      id: 1
 SELECT_type: SIMPLE
    table: group_message
     type: range
possible_keys: NULL
     key: idx_gid_uid_gc
   key_len: 4
     ref: NULL
     rows: 10
    Extra: Using index for group-by
1 row in set (0.00 sec)

我們可以很清晰的看到,執(zhí)行計(jì)劃中的 Extra 信息為“Using index for group-by”,這代表什么意思?為什么我沒有進(jìn)行 GROUP BY 操作的時(shí)候,執(zhí)行計(jì)劃中會告訴我這里通過索引進(jìn)行了 GROUP BY 呢?其實(shí)這就是于 DISTINCT 的實(shí)現(xiàn)原理相關(guān)的,在實(shí)現(xiàn) DISTINCT的過程中,同樣也是需要分組的,然后再從每組數(shù)據(jù)中取出一條返回給客戶端。而這里的 Extra 信息就告訴我們,MySQL 利用松散索引掃描就完成了整個(gè)操作。當(dāng)然,如果 MySQL Query Optimizer 要是能夠做的再人性化一點(diǎn)將這里的信息換成“Using index for distinct”那就更好更容易讓人理解了,呵呵。

2.我們再來看看通過緊湊索引掃描的示例:

sky@localhost : example 11:03:53> EXPLAIN SELECT DISTINCT user_id 
  -> FROM group_message
  -> WHERE group_id = 2G
*************************** 1. row ***************************
      id: 1
 SELECT_type: SIMPLE
    table: group_message
     type: ref
possible_keys: idx_gid_uid_gc
     key: idx_gid_uid_gc
   key_len: 4
     ref: const
     rows: 4
    Extra: Using WHERE; Using index
1 row in set (0.00 sec)

這里的顯示和通過緊湊索引掃描實(shí)現(xiàn) GROUP BY 也完全一樣。實(shí)際上,這個(gè) Query 的實(shí)現(xiàn)過程中,MySQL 會讓存儲引擎掃描 group_id = 2 的所有索引鍵,得出所有的 user_id,然后利用索引的已排序特性,每更換一個(gè) user_id 的索引鍵值的時(shí)候保留一條信息,即可在掃描完所有 gruop_id = 2 的索引鍵的時(shí)候完成整個(gè) DISTINCT 操作。

3.下面我們在看看無法單獨(dú)使用索引即可完成 DISTINCT 的時(shí)候會是怎樣:

sky@localhost : example 11:04:40> EXPLAIN SELECT DISTINCT user_id 
  -> FROM group_message
  -> WHERE group_id > 1 AND group_id < 10G
*************************** 1. row ***************************
      id: 1
 SELECT_type: SIMPLE
    table: group_message
     type: range
possible_keys: idx_gid_uid_gc
     key: idx_gid_uid_gc
   key_len: 4
     ref: NULL
     rows: 32
    Extra: Using WHERE; Using index; Using temporary
1 row in set (0.00 sec)

當(dāng) MySQL 無法僅僅依賴索引即可完成 DISTINCT 操作的時(shí)候,就不得不使用臨時(shí)表來進(jìn)行相應(yīng)的操作了。但是我們可以看到,在 MySQL 利用臨時(shí)表來完成 DISTINCT 的時(shí)候,和處理 GROUP BY 有一點(diǎn)區(qū)別,就是少了 filesort。實(shí)際上,在 MySQL 的分組算法中,并不一定非要排序才能完成分組操作的,這一點(diǎn)在上面的 GROUP BY 優(yōu)化小技巧中我已經(jīng)提到過了。實(shí)際上這里 MySQL 正是在沒有排序的情況下實(shí)現(xiàn)分組最后完成 DISTINCT 操作的,所以少了 filesort 這個(gè)排序操作。

4.最后再和 GROUP BY 結(jié)合試試看:

sky@localhost : example 11:05:06> EXPLAIN SELECT DISTINCT max(user_id) 
  -> FROM group_message
  -> WHERE group_id > 1 AND group_id < 10
  -> GROUP BY group_idG
*************************** 1. row ***************************
      id: 1
 SELECT_type: SIMPLE
    table: group_message
     type: range
possible_keys: idx_gid_uid_gc
     key: idx_gid_uid_gc
   key_len: 4
     ref: NULL
     rows: 32
    Extra: Using WHERE; Using index; Using temporary; Using filesort
1 row in set (0.00 sec)

最后我們再看一下這個(gè)和 GROUP BY 一起使用帶有聚合函數(shù)的示例,和上面第三個(gè)示例相比,可以看到已經(jīng)多了 filesort 排序操作了,正是因?yàn)槲覀兪褂昧?MAX 函數(shù)的緣故。要取得分組后的 MAX 值,又無法使用索引完成操作,只能通過排序才行了。

mysql distinct和group by誰更好
1,測試前的準(zhǔn)備

//準(zhǔn)備一張測試表 
mysql> CREATE TABLE `test_test` ( 
 ->  `id` int(11) NOT NULL auto_increment, 
 ->  `num` int(11) NOT NULL default '0', 
 ->  PRIMARY KEY (`id`) 
 -> ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

  

Query OK, 0 rows affected (0.05 sec) 

 

mysql> delimiter || //改變mysql命令結(jié)束符為|| 
 
//建個(gè)儲存過程向表中插入10W條數(shù)據(jù) 
mysql> create procedure p_test(pa int(11)) 
 -> begin 
 -> 
 -> declare max_num int(11) default 100000; 
 -> declare i int default 0; 
 -> declare rand_num int; 
 -> 
 -> select count(id) into max_num from test_test; 
 -> 
 -> while i < pa do 
 ->     if max_num < 100000 then 
 ->         select cast(rand()*100 as unsigned) into rand_num; 
 ->         insert into test_test(num)values(rand_num); 
 ->     end if; 
 ->     set i = i +1; 
 -> end while; 
 -> end|| 
Query OK, 0 rows affected (0.00 sec) 

 

mysql> call p_test(100000)|| 
Query OK, 1 row affected (5.66 sec) 

 

mysql> delimiter ;//改變mysql命令結(jié)束符為; 
mysql> select count(id) from test_test; //數(shù)據(jù)都進(jìn)去了 
+-----------+ 
| count(id) | 
+-----------+ 
|  100000 | 
+-----------+ 
1 row in set (0.00 sec) 

 

mysql> show variables like "%pro%";  //查看一下,記錄執(zhí)行的profiling是不是開啟動(dòng)了,默認(rèn)是不開啟的 
+---------------------------+-------+ 
| Variable_name       | Value | 
+---------------------------+-------+ 
| profiling         | OFF  | 
| profiling_history_size  | 15  | 
| protocol_version     | 10  | 
| slave_compressed_protocol | OFF  | 
+---------------------------+-------+ 
4 rows in set (0.00 sec) 

 

mysql> set profiling=1;      //開啟 
Query OK, 0 rows affected (0.00 sec) 

2,測試

//做了4組測試 
mysql> select distinct(num) from test_test; 
mysql> select num from test_test group by num; 
 
mysql> show profiles;  //查看結(jié)果 
+----------+------------+-------------------------------------------+ 
| Query_ID | Duration  | Query                   | 
+----------+------------+-------------------------------------------+ 
|    1 | 0.07298225 | select distinct(num) from test_test    | 
|    2 | 0.07319975 | select num from test_test group by num  | 
|    3 | 0.07313525 | select num from test_test group by num  | 
|    4 | 0.07317725 | select distinct(num) from test_test    | 
|    5 | 0.07275200 | select distinct(num) from test_test    | 
|    6 | 0.07298600 | select num from test_test group by num  | 
|    7 | 0.07500700 | select num from test_test group by num  | 
|    8 | 0.07331325 | select distinct(num) from test_test    | 
|    9 | 0.57831575 | create index num_index on test_test (num) | //在這兒的時(shí)候,我加了索引 
|    10 | 0.00243550 | select distinct(num) from test_test    | 
|    11 | 0.00121975 | select num from test_test group by num  | 
|    12 | 0.00116550 | select distinct(num) from test_test    | 
|    13 | 0.00107650 | select num from test_test group by num  | 
+----------+------------+-------------------------------------------+ 
13 rows in set (0.00 sec) 

上面的1-8是4組數(shù)據(jù),并且是沒有加索引的,從中我們可以看出,distinct比group by 會好一點(diǎn)點(diǎn)
10-13是2組數(shù)據(jù),是加了索引以后的,從中我們可以看出,group by 比distinct 會好一點(diǎn)點(diǎn)
一般情況,數(shù)據(jù)量比較大的表,關(guān)聯(lián)字段都會加索引的,,并且加索引后檢索時(shí)間只有以前的六分之一左右。

相關(guān)文章

  • Mysql中強(qiáng)大的group?by語句解析

    Mysql中強(qiáng)大的group?by語句解析

    這篇文章主要介紹了Mysql中強(qiáng)大的group?by語句解析,GROUP?BY?語句根據(jù)一個(gè)或多個(gè)列對結(jié)果集進(jìn)行分組。在分組的列上我們可以使用?COUNT,?SUM,?AVG,等函數(shù),需要的朋友可以參考下
    2023-07-07
  • mysql數(shù)據(jù)庫重命名語句分享

    mysql數(shù)據(jù)庫重命名語句分享

    這篇文章主要介紹了mysql數(shù)據(jù)庫重命名語句救命示例,語句中的數(shù)據(jù)庫表前綴換成自己的就可以了,大家參考使用吧
    2014-01-01
  • MySQL Json類型字段IN查詢分組優(yōu)化

    MySQL Json類型字段IN查詢分組優(yōu)化

    這篇文章主要為大家介紹了MySQL Json類型字段IN查詢分組優(yōu)化,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • IOS 數(shù)據(jù)庫升級數(shù)據(jù)遷移的實(shí)例詳解

    IOS 數(shù)據(jù)庫升級數(shù)據(jù)遷移的實(shí)例詳解

    這篇文章主要介紹了IOS 數(shù)據(jù)庫升級數(shù)據(jù)遷移的實(shí)例詳解的相關(guān)資料,這里提供實(shí)例幫助大家解決數(shù)據(jù)庫升級及數(shù)據(jù)遷移的問題,需要的朋友可以參考下
    2017-07-07
  • MySQL忘記了root用戶密碼如何重置的解決方案

    MySQL忘記了root用戶密碼如何重置的解決方案

    MySQL是當(dāng)前被廣泛使用的關(guān)系型數(shù)據(jù)庫,MySQL需要設(shè)置root用戶的密碼,用于驗(yàn)證登錄數(shù)據(jù)庫服務(wù)器,但往往可能由于各種原因?qū)е峦浟嗽撁艽a,于是就有了本次分享的內(nèi)容,MySQL忘記root密碼的解決方案,需要的朋友可以參考下
    2024-05-05
  • ERROR CODE: 1175 YOU ARE USING SAFE UPDATE MODE AN

    ERROR CODE: 1175 YOU ARE USING SAFE UPDATE MODE AN

    這篇文章主要介紹了ERROR CODE: 1175 YOU ARE USING SAFE UPDATE MODE AN,本文是在MySQL Workbench的環(huán)境操作,需要的朋友可以參考下
    2014-11-11
  • mysql 8.0.12 快速安裝教程

    mysql 8.0.12 快速安裝教程

    這篇文章主要為大家詳細(xì)介紹了mysql 8.0.12的快速安裝教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-08-08
  • Mysql中的自連接問題

    Mysql中的自連接問題

    這篇文章主要介紹了Mysql中的自連接問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-05-05
  • MySQL解析JSON格式字段并取出部分值方式

    MySQL解析JSON格式字段并取出部分值方式

    這篇文章主要介紹了MySQL解析JSON格式字段并取出部分值方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • mysql字段為null為何不能使用!=

    mysql字段為null為何不能使用!=

    這篇文章主要介紹了mysql字段為null為何不能使用!=問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-05-05

最新評論

修水县| 韶山市| 利川市| 定州市| 广西| 辽阳县| 江门市| 准格尔旗| 阳曲县| 汉沽区| 牟定县| 宝丰县| 天镇县| 九龙县| 龙山县| 贵溪市| 大埔区| 大冶市| 黄梅县| 玉龙| 民乐县| 商丘市| 综艺| 登封市| 宁强县| 上栗县| 弥渡县| 巨鹿县| 郁南县| 华池县| 侯马市| 东安县| 贵阳市| 游戏| 松江区| 靖西县| 鄯善县| 扬州市| 高要市| 兰州市| 和静县|