MySQL中的數據去重,該用DISTINCT還是GROUP BY?
在日常工作中,數據庫查詢操作無處不在,而處理數據中的重復項與分組匯總是非常常見的需求。
MySQL 提供了兩種常見的方式來管理和檢索唯一值:SELECT DISTINCT 和 GROUP BY。這兩者雖然在生成輸出上可能相似,但用途與性能各有不同,使用場景也有所區分。
這篇文章帶大家將從功能、性能以及實際應用等方面詳細介紹 DISTINCT 和 GROUP BY 的差異,并結合具體的示例數據來理解其使用場景。
SELECT DISTINCT
DISTINCT 是一個用于去重的關鍵字。SELECT DISTINCT 語句用于從結果集中刪除重復行,只返回唯一值。因此,在需要僅獲取數據的唯一部分時,DISTINCT 是一種簡單高效的方式。
基本語法
SELECT DISTINCT column1, column2
FROM table_name;參數說明:
- column1, column2:要檢索的字段名。
- table_name:查詢的表名。
特性說明
- DISTINCT 可以基于單列或多列進行去重,只有多列的值完全相同時,才會被判定為重復行。
- 在DISTINCT中,NULL 被視為一個獨立的值,因此即使列中有多個 NULL 值,結果中只會保留一個 NULL。
GROUP BY
GROUP BY 是一個用于分組的子句,通常與聚合函數配合使用以對分組后的數據進行匯總處理。它按指定列的值將行劃分為不同的組。
基本語法
SELECT column1, aggregate_function(column_name)
FROM table_name
WHERE condition
GROUP BY column1, column2, ...;參數說明:
- column1, column2:分組的字段。
- aggregate_function(column_name) :用于對分組內的行進行計算的聚合函數,例如 COUNT, SUM, AVG 等。
- table_name:查詢的表名字。
- condition:可選,用于過濾行,在分組之前應用。
- GROUP BY column1, column2... :定義用于分組的字段,具有相同值的行被分配到同一個組。
示例表結構與數據:
為了便于說明,我們定義兩個表 customers 和 orders,并插入一些示例數據。
創建表:
CREATE TABLE customers (
customer_id INT PRIMARY KEY,
nameVARCHAR(255) NOTNULL,
city VARCHAR(255) NOTNULL
);
INSERTINTO customers (customer_id, name, city) VALUES
(1, 'John Doe', 'New York'),
(2, 'Jane Smith', 'London'),
(3, 'Mike Brown', 'Paris'),
(2, 'Jane Smith', 'London'); -- 存在重復項
CREATETABLE orders (
order_id INT PRIMARY KEY,
customer_id INTNOTNULL,
product VARCHAR(255) NOTNULL,
price DECIMAL(10,2) NOTNULL,
FOREIGNKEY (customer_id) REFERENCES customers(customer_id)
);
INSERTINTO orders (order_id, customer_id, product, price) VALUES
(1, 1, 'Phone', 100.00),
(2, 2, 'Laptop', 500.00),
(3, 1, 'Tablet', 200.00),
(4, 2, 'Watch', 150.00);SELECT DISTINCT與GROUP BY使用對比
示例 1:檢索唯一的客戶城市
場景:我們希望查詢 customers 表中的唯一城市,不關心重復的城市名稱。
使用 DISTINCT:
SELECT DISTINCT city
FROM customers;輸出:
city
-----
New York
London
ParisSQL 查詢去除了數據集中重復的城市,只返回唯一值,簡單直觀。
示例 2:按客戶城市統計訂單數量
場景:我們希望統計每個城市對應的訂單數量,涉及分組統計。
使用 GROUP BY:
SELECT city, COUNT(*) AS order_count
FROM customers c
INNER JOIN orders o ON c.customer_id = o.customer_id
GROUP BY city;輸出:
city order_count
------------------------
London 2
New York 2SQL 查詢通過 GROUP BY 以城市分組,并結合 COUNT 聚合函數統計每組的訂單數量,提供了更豐富的匯總信息。
SELECT DISTINCT 與 GROUP BY 的性能分析
雖然 DISTINCT 和 GROUP BY 都會涉及底層的分組操作,但在某些情況下,它們可以互換使用,而在性能、功能上的表現會有所偏差。
兩者實現的相似性
對于以下兩條查詢:
SELECT DISTINCT int1_index FROM test_table;
SELECT int1_index FROM test_table GROUP BY int1_index;在某些情況下(如 int1_index 上有索引),兩者使用相同的執行計劃。例如,通過以下 EXPLAIN 分析,查詢會通過索引掃描優化:
mysql> explain select distinct int1_index from test_distinct_groupby;
mysql> explain select int1_index from test_distinct_groupby group by int1_index;兩者結果中 Extra 字段顯示 Using index for group-by,說明索引用于優化查詢,效率相當。
GROUP BY的隱式排序問題
在 MySQL 8.0 之前,GROUP BY 默認對結果進行隱式排序。這可能導致額外的排序操作(filesort),增加了查詢開銷。在無顯式排序要求時,DISTINCT 的性能會優于 GROUP BY。
例如:
SELECT int6_random FROM test_table GROUP BY int6_random;通過 EXPLAIN 查詢,可以看到隱式排序增加了開銷:
Extra: Using filesort從 MySQL 8.0 開始,GROUP BY 不再強制進行隱式排序,性能接近 DISTINCT,尤其是在無索引的大數據場景下,二者效率更加一致。
SELECT DISTINCT 與 GROUP BY 的應用場景及差異
功能和目的對比:
功能 | SELECT DISTINCT | GROUP BY |
目的 | 去重 | 分組并聚合數據 |
是否支持聚合函數 | 否 | 是 |
排序行為 | 否(可選) | 是(默認排序,8.0后優化) |
性能 | 無索引場景更高效 | 無索引場景稍慢(排序) |
語法復雜度 | 簡單 | 較復雜 |
適用場景
根據具體需求選擇 DISTINCT 或 GROUP BY:
- 使用SELECT DISTINCT:
- 當僅需要去除重復項,返回唯一值時。
- 適用于簡單查詢場景。
- 使用GROUP BY:
- 當需要按特定條件分組并對分組內的數據進行匯總或聚合(如 COUNT, SUM, AVG)時。
- 適合復雜的業務場景,支持更多靈活的操作,如結合 HAVING 子句篩選分組后的結果。
結論
SELECT DISTINCT 和 GROUP BY 是兩種功能強大的工具,用于不同類型的 SQL 查詢需求:
- DISTINCT 適合簡單去重,避免數據重復。
- GROUP BY 更注重分組數據并對分組進行匯總分析。
在 MySQL 8.0 后,性能差距進一步縮小,但從語義清晰度與靈活性來看,GROUP BY 在處理復雜業務場景時更勝一籌。選擇使用哪種方式應根據具體應用場景而定。






























