面試突擊63:MySQL 中如何去重?
在 MySQL 中,最常見的去重方法有兩個:使用 distinct 或使用 group by,那它們有什麼區別呢?接下來我們一起來看。
1.建立測試資料
sql
-- 建立測試表
drop table if exists pageview;
create table pageview(
id bigint primary key auto_increment comment '自增主鍵',
aid bigint not null comment '文章ID',
uid bigint not null comment '(訪問)使用者ID',
createtime datetime default now() comment '建立時間'
) default charset='utf8mb4';
-- 新增測試資料
insert into pageview(aid,uid) values(1,1);
insert into pageview(aid,uid) values(1,1);
insert into pageview(aid,uid) values(2,1);
insert into pageview(aid,uid) values(2,2);
最終展現效果如下:
2.distinct 使用
distinct 基本語法如下:
sql
SELECT DISTINCT column_name,column_name FROM table_name;
2.1 單列去重
我們先用 distinct 實現單列去重,根據 aid(文章 ID)去重,具體實現如下:
2.2 多列去重
除了單列去重之外,distinct 還支援多列(兩列及以上)去重,我們根據 aid(文章 ID)和 uid(使用者 ID)聯合去重,具體實現如下:
2.3 聚合函式+去重
使用 distinct + 聚合函式去重,計算 aid 去重之後的總條數,具體實現如下:
3.group by 使用
group by 基礎語法如下:
sql
SELECT column_name,column_name FROM table_name
WHERE column_name operator value
GROUP BY column_name
3.1 單列去重
根據 aid(文章 ID)去重,具體實現如下: 與 distinct 相比 group by 可以顯示更多的列,而 distinct 只能展示去重的列。
3.2 多列去重
根據 aid(文章 ID)和 uid(使用者 ID)聯合去重,具體實現如下:
3.3 聚合函式 + group by
統計每個 aid 的總數量,SQL 實現如下: 從上述結果可以看出,使用 group by 和 distinct 加 count 的查詢語義是完全不同的,distinct + count 統計的是去重之後的總數量,而 group by + count 統計的是分組之後的每組資料的總數。
4.distinct 和 group by 的區別
官方文件在描述 distinct 時提到:在大多數情況下 distinct 是特殊的 group by,如下圖所示: 官方文件地址:http://dev.mysql.com/doc/refman/8.0/en/distinct-optimization.html 但二者還是有一些細微的不同的,比如以下幾個。
區別1:查詢結果集不同
當使用 distinct 去重時,查詢結果集中只有去重列資訊,如下圖所示: 當你試圖新增非去重欄位(查詢)時,SQL 會報錯如下圖所示: 而使用 group by 排序可以查詢一個或多個欄位,如下圖所示:
區別2:使用業務場景不同
統計去重之後的總數量需要使用 distinct,而統計分組明細,或在分組明細的基礎上新增查詢條件時,就得使用 group by 了。 使用 distinct 統計某列去重之後的總數量: 統計分組之後數量大於 2 的文章,就要使用 group by 了,如下圖所示:
區別3:效能不同
如果去重的欄位有索引,那麼 group by 和 distinct 都可以使用索引,此情況它們的效能是相同的;而當去重的欄位沒有索引時,distinct 的效能就會高於 group by,因為在 MySQL 8.0 之前,group by 有一個隱藏的功能會進行預設的排序,這樣就會觸發 filesort 從而導致查詢效能降低。
總結
大部分場景下 distinct 是特殊的 group by,但二者也有細微的區別,比如它們在查詢結果集上、使用的具體業務場景上,以及效能上都是不同的。
參考 & 鳴謝
zhuanlan.zhihu.com/p/384840662
是非審之於己,譭譽聽之於人,得失安之於數。
公眾號:Java面試真題解析
- 面試官:什麼是雙親委派模型?
- 面試官:熔斷和降級有什麼區別?
- 寬表為什麼橫行?
- 有沒有完全自主的國產化資料庫技術
- 面試突擊64:瞭解 HTTP 協議嗎?
- 面試突擊80:說一下 Spring 中 Bean 的生命週期?
- 面試突擊89:事務隔離級別和傳播機制有什麼區別?
- 面試突擊82:SpringBoot 中如何操作事務?
- 面試突擊87:說一下 Spring 事務傳播機制?
- 面試突擊81:什麼是跨域問題?如何解決?
- 面試突擊71:GET 和 POST 有什麼區別?
- 面試突擊70:什麼是粘包和半包?怎麼解決?
- 面試突擊68:為什麼 TCP 需要 3 次握手?
- 面試突擊66:請求轉發和請求重定向有什麼區別?
- 面試突擊63:MySQL 中如何去重?
- 面試突擊65:為什麼要用HTTPS?它有什麼優點?
- 面試突擊62:group by 有哪些注意事項?
- 面試突擊53:常見的 HTTP 狀態碼有哪些?
- 面試突擊61:說一下MySQL事務隔離級別?
- 面試突擊52:什麼是三正規化?它有什麼用?