DISTINCT 會觸發全量排序,大表效能差;且只能對「選取欄位全部相同」去重。若需「指定欄位去重並保留其他欄位」,GROUP BY 是正解。
-- 以 A 為去重鍵,保留 B、C 的「首筆」值
SELECT A, MIN(B) AS B, MIN(C) AS C, COUNT(*) AS 重複次數
FROM t
GROUP BY A
HAVING COUNT(*) >= 1; -- =1 唯一值,>1 重複值
| 需求 | HAVING 條件 | 說明 |
|---|---|---|
| 只顯示重複資料 | COUNT(*) > 1 | 找出髒資料 |
| 去重並保留第一筆 | COUNT(*) >= 1 | 配合 MIN/MAX 取代表值 |
| 找出重複超過 N 次 | COUNT(*) > N | 嚴重重複排查 |
-- GROUP BY 版
SELECT brand, COUNT(*) FROM tab_commbaseinfo GROUP BY brand HAVING COUNT(*) = 1;
-- 平均 0.453 秒
-- DISTINCT 版
SELECT DISTINCT brand FROM tab_commbaseinfo;
-- 平均 0.39 秒
結論:單純去重 DISTINCT 略快;但 GROUP BY 提供聚合統計、保留其他欄位、條件過濾等 DISTINCT 無法做到的功能,綜合效能優於「DISTINCT + 子查詢」組合。
SELECT * FROM (
SELECT t.*, ROW_NUMBER() OVER (PARTITION BY brand ORDER BY id) rn
FROM tab_commbaseinfo t
) WHERE rn = 1;
此法可保留完整原始行 (非聚合值),且可指定保留邏輯 (最新/最舊/最大金額等)。
GROUP BY 欄位必須包含 SELECT 非聚合欄位,否則 ORA-00979。HAVING 只能用於聚合條件,非聚合條件請放 WHERE。CREATE TABLE new AS SELECT ... GROUP BY ... 避免排序溢位 TEMP。根據業務需求選擇:單純去重用 DISTINCT,需統計/保留其他欄位用 GROUP BY,需保留完整行用 ROW_NUMBER()。