国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

Mysql|Sql Server|Oracle|Redis|MongoDB|PostgreSQL|Sqlite|DB2|mariadb|Access|數據庫技術|

服務器之家 - 數據庫 - Mysql - MySQL中distinct語句的基本原理及其與group by的比較

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

2020-05-31 15:26海底蒼鷹 Mysql

這篇文章主要介紹了MySQL中distinct語句的基本原理及其與group by的比較,一般情況下來說group by和distinct的實現原理相近且性能稍好,需要的朋友可以參考下

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

下面我們就通過幾個簡單的 Query 示例來展示一下 DISTINCT 的實現。

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

?
1
2
sky@localhost : example 11:03:41> EXPLAIN SELECT DISTINCT group_id
  -> FROM group_messageG
?
1
2
3
4
5
6
7
8
9
10
11
12
*************************** 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í)行計劃中的 Extra 信息為“Using index for group-by”,這代表什么意思?為什么我沒有進行 GROUP BY 操作的時候,執(zhí)行計劃中會告訴我這里通過索引進行了 GROUP BY 呢?其實這就是于 DISTINCT 的實現原理相關的,在實現 DISTINCT的過程中,同樣也是需要分組的,然后再從每組數據中取出一條返回給客戶端。而這里的 Extra 信息就告訴我們,MySQL 利用松散索引掃描就完成了整個操作。當然,如果 MySQL Query Optimizer 要是能夠做的再人性化一點將這里的信息換成“Using index for distinct”那就更好更容易讓人理解了,呵呵。

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

?
1
2
3
sky@localhost : example 11:03:53> EXPLAIN SELECT DISTINCT user_id
  -> FROM group_message
  -> WHERE group_id = 2G
?
1
2
3
4
5
6
7
8
9
10
11
12
*************************** 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)

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

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

?
1
2
3
sky@localhost : example 11:04:40> EXPLAIN SELECT DISTINCT user_id
  -> FROM group_message
  -> WHERE group_id > 1 AND group_id < 10G
?
1
2
3
4
5
6
7
8
9
10
11
12
*************************** 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)

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

4.最后再和 GROUP BY 結合試試看:

?
1
2
3
4
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
2
3
4
5
6
7
8
9
10
11
12
*************************** 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)

最后我們再看一下這個和 GROUP BY 一起使用帶有聚合函數的示例,和上面第三個示例相比,可以看到已經多了 filesort 排序操作了,正是因為我們使用了 MAX 函數的緣故。要取得分組后的 MAX 值,又無法使用索引完成操作,只能通過排序才行了。

mysql distinct和group by誰更好
1,測試前的準備

?
1
2
3
4
5
6
//準備一張測試表
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 ;

  

?
1
Query OK, 0 rows affected (0.05 sec)

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
mysql> delimiter || //改變mysql命令結束符為||
 
//建個儲存過程向表中插入10W條數據
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||
?
1
Query OK, 0 rows affected (0.00 sec)

 

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

 

?
1
2
mysql> delimiter ;//改變mysql命令結束符為;
mysql> select count(id) from test_test; //數據都進去了
?
1
2
3
4
5
6
+-----------+
| count(id) |
+-----------+
|  100000 |
+-----------+
1 row in set (0.00 sec)

 

?
1
mysql> show variables like "%pro%";  //查看一下,記錄執(zhí)行的profiling是不是開啟動了,默認是不開啟的
?
1
2
3
4
5
6
7
8
9
+---------------------------+-------+
| Variable_name       | Value |
+---------------------------+-------+
| profiling         | OFF  |
| profiling_history_size  | 15  |
| protocol_version     | 10  |
| slave_compressed_protocol | OFF  |
+---------------------------+-------+
4 rows in set (0.00 sec)

 

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

2,測試

?
1
2
3
4
5
//做了4組測試
mysql> select distinct(num) from test_test;
mysql> select num from test_test group by num;
 
mysql> show profiles;  //查看結果
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
+----------+------------+-------------------------------------------+
| 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) | //在這兒的時候,我加了索引
|    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組數據,并且是沒有加索引的,從中我們可以看出,distinct比group by 會好一點點
10-13是2組數據,是加了索引以后的,從中我們可以看出,group by 比distinct 會好一點點
一般情況,數據量比較大的表,關聯字段都會加索引的,,并且加索引后檢索時間只有以前的六分之一左右。

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 中文字幕在线观看日韩 | 色在线电影 | 亚洲综合视频在线观看 | 黄色一级片在线观看 | 亚洲性人人天天夜夜摸 | 午夜小电影| 91精品一久久香蕉国产线看观看新通道出现 | 欧美国产日韩一区 | 国产精品视屏 | 欧美黄页| 久久久精品国产 | 日韩一片 | 91精品久久| 久久久国产一区二区三区 | 午夜av毛片| 亚洲一区二区三区精品动漫 | 国产高潮失禁喷水爽网站 | 91国自产精品中文字幕亚洲 | 国产精品色一区二区三区 | 久久久久久av | 四季久久免费一区二区三区四区 | 热久久这里只有精品 | 久久一区二 | 丁香久久 | 色综合久久久 | 亚洲欧洲在线观看 | 天天综合天天做天天综合 | 欧美国产精品一区 | 亚洲精品日日夜夜 | 成人在线播放 | 在线视频 中文字幕 | 欧美日韩一区二区电影 | 久久五月视频 | 国产一区中文字幕 | 欧美日韩精品一区二区在线观看 | 亚洲成a人| 日韩激情网 | 国产一区久久久 | 嫩呦国产一区二区三区av | 久久露脸国产精品 | 亚洲视频在线不卡 |