HAVING 對 GROUP BY 結果集分組進行過濾,條件僅允許:常數、聚合函數、GROUP BY 中的欄位。
SELECT a.empno FROM emp a
WHERE a.empno NOT IN (SELECT empno FROM emp1 WHERE job='SALE');
SELECT a.empno FROM emp a, emp1 b
WHERE a.empno = b.empno(+)
AND b.empno IS NULL
AND b.job = 'SALE';
原理:外部聯結保留主表所有行,無匹配時從表欄位為 NULL。利用索引驅動,速度大幅提升。
假設表 TBL,主鍵 (COL1, COL2),有索引。
CREATE TABLE tbl_tmp AS SELECT DISTINCT * FROM tbl;
TRUNCATE TABLE tbl;
INSERT INTO tbl SELECT * FROM tbl_tmp;
⚠️ 千萬級資料生產環境不可行,IO 開銷過大。
DELETE FROM tbl
WHERE rowid IN (
SELECT a.rowid FROM tbl a, tbl b
WHERE a.rowid > b.rowid
AND a.col1 = b.col1 AND a.col2 = b.col2);
-- 保留最大 ROWID
DELETE FROM tbl a
WHERE rowid NOT IN (
SELECT MAX(b.rowid) FROM tbl b
WHERE a.col1 = b.col1 AND a.col2 = b.col2);
-- 或使用 MIN 配合 >
DELETE FROM tbl a
WHERE rowid < (
SELECT MAX(b.rowid) FROM tbl b
WHERE a.col1 = b.col1 AND a.col2 = b.col2);
DELETE FROM tbl
WHERE rowid NOT IN (
SELECT MAX(rowid) FROM tbl t
GROUP BY t.col1, t.col2);
-- 僅處理有重複的群組
DELETE FROM tbl
WHERE (col1, col2) IN (
SELECT col1, col2 FROM tbl
GROUP BY col1, col2 HAVING COUNT(*) > 1)
AND rowid NOT IN (
SELECT MIN(rowid) FROM tbl
GROUP BY col1, col2 HAVING COUNT(*) > 1);
✅ 利用索引加速 GROUP BY,僅掃描重複群組,大表效能最佳。
大交易報錯:ORA-01555: snapshot too old (rollback segment too small)
解法:預先指定足夠大的 Rollback Segment
SET TRANSACTION USE ROLLBACK SEGMENT roll_abc;
DELETE FROM table_name WHERE ...;
COMMIT; -- 交易結束自動釋放指定
REBUILD INDEX 或 TRUNCATE TABLE(同步清理索引碎片)IMP 匯入時 View 可能因基底表尚未建立而失敗。雙階段策略:
# 階段 1:僅匯入結構(無資料)
imp jfcl/hfjf@ora1 file=expdata.dmp rows=N
# 階段 2:匯入結構+資料,忽略已存在物件
imp jfcl/hfjf@ora1 file=expdata.dmp full=Y buffer=64000 commit=Y ignore=Y
IGNORE=Y 確保第二階段不因物件存在而中斷,BUFFER=64000 每 64KB 提交一次加速。
這六大技巧涵蓋查詢優化、資料清理、交易控制、索引維護、遷移部署核心場景,是 Oracle DBA 與開發者的必備工具箱。實戰中需結合執行計畫、統計資訊、業務特性靈活組合應用。