通過 EXPLAIN 實測展示 DISTINCT 三種執行路徑:鬆散索引掃描、緊湊索引掃描、臨時表(無 filesort),並對比帶聚合函數時的 filesort 差異。
CREATE TABLE group_message ( group_id INT, user_id INT, gc INT, INDEX idx_gid_uid_gc (group_id, user_id, gc) ) ENGINE=InnoDB;
EXPLAIN SELECT DISTINCT group_id FROM group_message; -- Extra: Using index for group-by
利用複合索引首列 group_id 已排序特性,直接跳躍讀取每組第一筆,**無臨時表、無排序**。
EXPLAIN SELECT DISTINCT user_id FROM group_message WHERE group_id = 2; -- Extra: Using where; Using index
掃描 group_id=2 的所有索引鍵,利用索引有序性逐個讀取 user_id,值變化時保留一條。**同樣無臨時表、無排序**。
EXPLAIN SELECT DISTINCT user_id FROM group_message WHERE group_id > 1 AND group_id < 10; -- Extra: Using where; Using index; Using temporary
範圍查詢導致索引鍵不連續,需臨時表去重,**但無 Using filesort**,證明 MySQL 分組不強制排序。
EXPLAIN SELECT DISTINCT MAX(user_id) FROM group_message WHERE group_id > 1 AND group_id < 10 GROUP BY group_id; -- Extra: Using where; Using index; Using temporary; Using filesort
MAX() 需取組內最大值,無索引支援只能排序產生 filesort。
| 場景 | DISTINCT 耗時 | GROUP BY 耗時 | 結論 |
|---|---|---|---|
| 無索引 | ~0.073s | ~0.073s | DISTINCT 略快 |
| 加索引後 | ~0.0024s | ~0.0011s | GROUP BY 明顯更快 |
建議:大表關鍵字段務必加索引,索引後 GROUP BY 效能優勢明顯;無索引場景差異微小。