萬盛學電腦網

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

MySQL 重複數據查找與刪除全攻略:保留最新/最舊、單字段/多字段、臨時表/窗口函數四大模式

業務系統因缺乏唯一約束、重複提交、同步邏輯缺陷,產生大量重複記錄。刪除重複數據核心邏輯是:**定義「重複鍵」 → 標記「保留行」 → 刪除其餘**。本文提供四種成熟模式,覆蓋 MySQL 5.6 到 8.0 全版本。

模式一:經典子查詢(全版本通用,中小表)

-- 1. 查找全部重複記錄(按 title 判重)
SELECT * FROM t_info a
WHERE (SELECT COUNT(*) FROM t_info WHERE title = a.title) > 1
ORDER BY title DESC;

-- 2. 刪除重複,保留 ID 最大(最新)的一條
DELETE FROM t_info
WHERE id NOT IN (
    SELECT MAX(id) FROM t_info GROUP BY title
);

-- 3. 刪除重複,保留 ID 最小(最舊)的一條
DELETE FROM t_info
WHERE id NOT IN (
    SELECT MIN(id) FROM t_info GROUP BY title
);

注意: NOT IN 子查詢返回 NULL 會導致全表刪除,務必保證子查詢無 NULL(主鍵非空天然滿足)。大表子查詢效能差,見模式二。

模式二:臨時表中轉(大表、高併發安全)

-- 1. 建臨時表存保留行主鍵
CREATE TEMPORARY TABLE tmp_keep AS
SELECT MAX(id) AS keep_id FROM t_info GROUP BY title HAVING COUNT(*) > 1;

-- 2. 刪除(用 JOIN 替代 IN,優化器更穩定)
DELETE t FROM t_info t
LEFT JOIN tmp_keep k ON t.id = k.keep_id
WHERE k.keep_id IS NULL;

-- 3. 清理
DROP TEMPORARY TABLE tmp_keep;

優勢: 避免長事務鎖表,臨時表會話隔離,不影響主從複寫(若用 ROW 格式)。

模式三:多字段聯合去重(業務鍵組合)

-- 查找 (peopleId, seq) 組合重複
SELECT * FROM vitae a
WHERE (a.peopleId, a.seq) IN (
    SELECT peopleId, seq FROM vitae GROUP BY peopleId, seq HAVING COUNT(*) > 1
);

-- 刪除,保留 rowid 最小
DELETE a FROM vitae a
WHERE (a.peopleId, a.seq) IN (
    SELECT peopleId, seq FROM vitae GROUP BY peopleId, seq HAVING COUNT(*) > 1
) AND a.rowid NOT IN (
    SELECT MIN(rowid) FROM vitae GROUP BY peopleId, seq HAVING COUNT(*) > 1
);

模式四:MySQL 8.0 窗口函數(最優雅、最高效)

-- 1. 標記重複行序號
WITH ranked AS (
    SELECT
        id,
        title,
        ROW_NUMBER() OVER (PARTITION BY title ORDER BY id DESC) AS rn
    FROM t_info
)
-- 2. 直接刪除 rn > 1
DELETE FROM t_info
WHERE id IN (SELECT id FROM ranked WHERE rn > 1);

擴展: PARTITION BY title, category 多字段去重;ORDER BY created_at DESC 保留最新;RANK() 保留所有並列第一。

特殊場景:完全重複行(所有列相同)

-- 快速去重並保留一行
CREATE TABLE tmp_dedup AS SELECT DISTINCT * FROM source_table;
TRUNCATE TABLE source_table;
INSERT INTO source_table SELECT * FROM tmp_dedup;
DROP TABLE tmp_dedup;
-- 根治:加唯一索引 UNIQUE KEY uk_all (col1, col2, ...)

效能對比與選型建議

模式適用量級優點缺點
子查詢 IN/NOT IN< 10 萬行SQL 簡單大表極慢,NOT IN 陷阱
臨時表 + JOIN10 萬 - 1 億行可控、可分批、不阻塞主從需額外磁盤空間
窗口函數 (8.0+)任意量級單掃描、語義清晰、可並行需 8.0+,舊版本不可用
建表去重完全重複行最快需鎖表、外鍵依賴需處理

預防重複的系統性對策

  1. 資料庫層: 業務鍵加 UNIQUE INDEX,INSERT IGNORE / ON DUPLICATE KEY UPDATE。
  2. 應用層: 幂等性 Token(Redis SETNX)、前端防重複提交(按鈕置灰)。
  3. 同步層: Canal/Debezium 同步時按主鍵冪等寫入。
  4. 定期巡檢: 定時任務跑 SELECT COUNT(*)-COUNT(DISTINCT uk) FROM table 異常報警。

刪除重複數據是治標,**唯一約束 + 幂等設計** 才是治本。根據表量級、版本、業務窗口選擇合適模式,動手前必備份、驗證、分批,事後必加索引、審計來源。

copyright © 萬盛學電腦網 all rights reserved