大表 (億級) 使用 `DELETE ... WHERE ROWID NOT IN (SELECT MIN(ROWID) ... GROUP BY key)` 會導致:
CREATE TABLE xxfgs_sig AS
SELECT imeid,
MAX(dn) dn,
MAX(xlh) xlh,
MAX(pro_name) pro_name,
MAX(area_name) area_name,
MAX(brand) brand,
MAX(m_type) m_type
FROM xxfgs
GROUP BY imeid
HAVING COUNT(*) < 2; -- 僅保留本來就不重複的鍵
CREATE TABLE xxfgs_row AS SELECT MAX(rowid) AS rowdata, imeid FROM xxfgs GROUP BY imeid HAVING COUNT(*) > 1; -- 每個重複組保留一個 ROWID (最大值)
寫法 A:NOT IN (適合中等表)
DELETE FROM xxfgs WHERE rowid NOT IN (SELECT rowdata FROM xxfgs_row);
寫法 B:關聯子查詢 (適合大表,配合索引)
DELETE FROM xxfgs a WHERE a.rowid <> (SELECT rowdata FROM xxfgs_row b WHERE a.imeid = b.imeid);
建議在 `xxfgs_row(imeid)` 建立索引加速關聯。
INSERT INTO xxfgs_sig SELECT * FROM xxfgs a WHERE a.rowid IN (SELECT rowdata FROM xxfgs_row); -- 重命名/切換 DROP TABLE xxfgs; RENAME xxfgs_sig TO xxfgs;
| 優化點 | 說明 |
|---|---|
| 分批提交 | 大表刪除改用 PL/SQL 循環,每 5000-10000 行 COMMIT 一次 |
| 並行 DML | ALTER SESSION ENABLE PARALLEL DML; DELETE /*+ PARALLEL(8) */ ... |
| 索引輔助 | 去重鍵 (imeid) 建立索引,加速 GROUP BY 與關聯刪除 |
| 離線操作 | 維護窗口執行,避免業務高峰 |
| 監控 Undo | V$UNDOSTAT 觀察 Undo 產生率,調整 UNDO_RETENTION |
DELETE FROM xxfgs
WHERE rowid IN (
SELECT rowid FROM (
SELECT rowid,
ROW_NUMBER() OVER (PARTITION BY imeid ORDER BY rowid) AS rn
FROM xxfgs
) WHERE rn > 1
);
-- 單條 SQL 完成,優化器可選擇 HASH GROUP BY 避免排序