distinct
實際上和
group by
的操作非常相似,只不過是在
group by
之後的每組中只取出一條記錄而已。所以,
distinct
的實現和
group by
的實現也基本差不多,沒有太大的區別。同樣可以通過鬆散索引掃瞄或者是緊湊索引掃瞄來實現,當然,在無法僅僅使用索引即能完成
distinct
的時候,
mysql
只能通過臨時表來完成。但是,和
group by
有一點差別的是,
distinct
並不需要進行排序。也就是說,在僅僅只是
distinct
操作的query
如果無法僅僅利用索引完成操作的時候,
mysql
會利用臨時表來做一次資料的「快取
」,但是不會對臨時表中的資料進行
filesort
操作。當然,如果我們在進行
distinct
的時候還使用了
group by
並進行了分組,並使用了類似於
max之類的聚合函式操作,就無法避免
filesort了。
下面我們就通過幾個簡單的
query
示例來展示一下
distinct
的實現。
1.首先看看通過鬆散索引掃瞄完成
distinct
的操作:
sky@localhost:
example 11:03
:41>explain select distinct group_id
->
from group_message\g
***************************
1.
row *************************** id
: 1
select_type:******
table:group_message
type:range
possible_keys:null
key:
idx_gid_uid_gc
key_len:
4ref:
null
rows:
10extra: using
index for
group-by 1
row in
set (0.00
sec)
我們可以很清晰的看到,執行計畫中的
extra
資訊為「
usingindex for group-by
」,這代表什麼意思?為什麼我沒有進行
group by
操作的時候,執行計畫中會告訴我這裡通過索引進行了
group by
呢?其實這就是於
distinct
的實現原理相關的,在實現
distinct
的過程中,同樣也是需要分組的,然後再從每組資料中取出一條返回給客戶端。而這裡的
extra
資訊就告訴我們,
mysql
利用鬆散索引掃瞄就完成了整個操作。當然,如果
mysqlquery optimizer
要是能夠做的再人性化一點將這裡的資訊換成
「using index for distinct
」那就更好更容易讓人理解了,呵呵。
2.
我們再來看看通過緊湊索引掃瞄的示例:
sky@localhost: example 11:
03:53> explain select distinct user_id
->from group_message
->where group_id = 2\g
***************************
1. row *************************** id
:1select_type: ******
table:group_message
type:ref
possible_keys:idx_gid_uid_gc
key:idx_gid_uid_gc
key_len:
4ref: const
rows:
4extra: using where; using index 1
row
inset (
0.00
sec)
這裡的顯示和通過緊湊索引掃瞄實現
group by
也完全一樣。實際上,這個
query
的實現過程中,
mysql
會讓儲存引擎掃瞄
group_id=2
的所有索引鍵,得出所有的
user_id
,然後利用索引的已排序特性,每更換乙個
user_id
的索引鍵值的時候保留一條資訊,即可在掃瞄完所有
gruop_id=2
的索引鍵的時候完成整個
distinct
操作。
3.下面我們在看看無法單獨使用索引即可完成
distinct
的時候會是怎樣:
sky@localhost: example 11:
04:40> explain select distinct user_id
->from group_message
->where group_id >
1and group_id <
10\g
***************************
1. row *************************** id
:1select_type: ******
table:group_message
type:range
possible_keys:idx_gid_uid_gc
key:idx_gid_uid_gc
key_len:
4ref: null
rows:
32extra: using where; using index; using temporary 1
row
inset (
0.00
sec)
當mysql
無法僅僅依賴索引即可完成
distinct
操作的時候,就不得不使用臨時表來進行相應的操作了。但是我們可以看到,在
mysql
利用臨時表來完成
distinct
的時候,和處理
group by
有一點區別,就是少了
filesort
。實際上,在
mysql
的分組演算法中,並不一定非要排序才能完成分組操作的,這一點在上面的
group by
優化小技巧中我已經提到過了。實際上這裡
mysql
正是在沒有排序的情況下實現分組最後完成
distinct
操作的,所以少了
filesort
這個排序操作。 4.
最後再和
group by
結合試試看:
sky@localhost: example 11:
05:06> explain select distinct max(user_id)
->from group_message
->where group_id >
1and group_id < 10
->group by group_id\g
***************************
1. row *************************** id
:1select_type: ******
table:group_message
type:range
possible_keys:idx_gid_uid_gc
key:idx_gid_uid_gc
key_len:
4ref: null
rows:
32extra: using where; using index; using temporary; usingfilesort 1
row
inset (
0.00
sec)
最後我們再看一下這個和
group by
一起使用帶有聚合函式的示例,和上面第三個示例相比,可以看到已經多了
filesort
排序操作了,因為我們使用了
max函式的緣故。 對於
distinct
的優化,和
group by
基本上一致的思路,關鍵在於利用好索引,在無法利用索引的時候,確保盡量不要在大結果集上面進行
distinct
操作,磁碟上面的
io操作和記憶體中的
io操作效能完全不是乙個數量級的差距。
MySQL distinct 返回其他字段
前倆天接到乙個 面試,被面試官的乙個複雜sql語句問題給問懵逼了,今日回想,還是準備的不夠充分啊!這次就查漏補缺吧!言歸正傳,在使用mysql時,有時需要查詢出某個欄位不重複的記錄,雖然mysql提供有distinct這個關鍵字來過濾掉多餘的重覆記錄只保留一條,但往往只用它來返回不重覆記錄的條數,而...
MySQL Distinct 去掉查詢結果重覆記錄
出處 使用 distinct 關鍵字可以去掉查詢中某個欄位的重覆記錄。語法 select distinct column from tb name例子 假定 user 表有如下記錄 uidusername1小李 2小張3小李 4小王5小李 6小張sql 語句 select distinct user...
MySQL DISTINCT 去重(過濾重複資料)
在使用 mysql select 語句查詢資料的時候返回的是所有匹配的行。例如,查詢 tb students info 表中所有 age 的執行結果如下所示。mysql select age from tb students info age 25 23 23 22 24 21 22 23 22 2...