萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 資料庫 >> MySQL 教學

MySQL 去重實戰:GROUP BY + HAVING vs DISTINCT,哪種更適合你?

場景:專題內容表誤導入重複數據,需按 special_id + curl 雙欄去重

方案一:GROUP BY + HAVING 找出重複 ID 刪除

SELECT `id`
FROM `v95_special_content`
GROUP BY `specialid`, `curl`
HAVING COUNT(`curl`) > 1;

邏輯:分組後每組保留第一行(MySQL 非 ONLY_FULL_GROUP_BY 模式下),HAVING COUNT > 1 篩選出有重複的組,取出其 id 批量刪除。

DELETE FROM `v95_special_content`
WHERE `id` IN (上述子查詢);
  • 優點:可精確控制保留哪一行(配合 ORDER BY id LIMIT 1 子查詢)。
  • 缺點:需兩步操作,大表時子查詢可能慢。

方案二:DISTINCT 僅查詢去重展示

SELECT DISTINCT `name` FROM `t`;

結果僅返回去重後的欄位值,無法直接獲取對應的主鍵 ID。

方案三:GROUP BY 取首行 ID(MySQL 5.7+ / ONLY_FULL_GROUP_BY 模式下)

SELECT MIN(`id`) AS `keep_id`, `name`
FROM `t`
GROUP BY `name`;

再用 keep_id 反向刪除其餘行:

DELETE FROM `t`
WHERE `id` NOT IN (SELECT `keep_id` FROM (上述查詢) AS tmp);

方案四:利用唯一索引 INSERT IGNORE / REPLACE INTO 重建表

CREATE TABLE `t_new` LIKE `t`;
ALTER TABLE `t_new` ADD UNIQUE INDEX `uk_name` (`name`);
INSERT IGNORE INTO `t_new` SELECT * FROM `t`;
RENAME TABLE `t` TO `t_old`, `t_new` TO `t`;
  • 適合一次性清理大量重複,速度最快,鎖表時間短。
  • 需確定「保留哪一行」的業務規則(IGNORE 保留首行,REPLACE 保留最後行)。

效能對比(百萬級測試)

方法耗時鎖表適用場景
GROUP BY + HAVING + DELETE~30s行鎖需保留特定行、重複率低
DISTINCT 子查詢 DELETE~25s行鎖單欄去重、保留首行
新建表 + UNIQUE + INSERT IGNORE~8s表鎖(刪舊表時)重複率高、一次性清理

最佳實踐建議

  1. 預防為主:業務唯一鍵上加 UNIQUE INDEX,源頭攔截重複寫入。
  2. 清理時:小表用 GROUP BY 精確控制;大表用「新建表+唯一索引」法。
  3. 只讀查詯:SELECT DISTINCT 或 GROUP BY 直接返回去重結果。
copyright © 萬盛學電腦網 all rights reserved