大量 `DELETE` 後,表 **High Water Mark (HWM) 不下降**,全表掃描仍讀取空塊,查詢效能不升反降。原因:**DELETE 僅標記行刪除、釋放塊內空間,不移動 HWM、不歸還Extent 給表空間**。
| 方案 | 適用版本 | 操作步驟 | 優點 | 缺點/風險 | 停機時間 |
|---|---|---|---|---|---|
| ANALYZE / DBMS_STATS | 9i/10g/11g+ | `ANALYZE TABLE t COMPUTE STATISTICS;` `EXEC DBMS_STATS.GATHER_TABLE_STATS('SCHEMA','T');` | 無鎖、秒級、不移動數據 | **不降 HWM、不釋放空間**,僅更新統計資訊讓 CBO 選對計畫 | 無 |
| EXP/IMP (傳統) / Data Pump (10g+) | 全版本 | `EXP ... TABLES=t` `DROP TABLE t` `IMP ... TABLES=t` | 徹底重建表、HWM 歸零、空間全釋放 | 需獨佔鎖、大表耗時長、索引/約束/權限需重建、觸發器失效 | 長 (大表小時級) |
| ALTER TABLE ... SHRINK SPACE (10g+) | 10g/11g/12c/19c/21c/23ai | `ALTER TABLE t ENABLE ROW MOVEMENT;` `ALTER TABLE t SHRINK SPACE [COMPACT];` `ALTER TABLE t DISABLE ROW MOVEMENT;` | **在線操作、移動行降 HWM、釋放空間、保留索引/約束/權限** | 需 `ROW MOVEMENT`、產生大量 Redo/Undo、長事務可能導致 Snapshot Too Old | 極短 (僅鎖定瞬間) |
-- 1. 建測試表、塞 100 萬行、刪 90%
CREATE TABLE t_shrink AS SELECT * FROM dba_objects WHERE rownum <= 1000000;
DELETE FROM t_shrink WHERE rownum <= 900000;
COMMIT;
-- 2. 觀察 HWM 與空間
SELECT blocks, empty_blocks, num_rows FROM user_tables WHERE table_name='T_SHRINK';
-- blocks 仍大,empty_blocks 增多
-- 3. 方案 A:統計資訊 (不降 HWM)
EXEC DBMS_STATS.GATHER_TABLE_STATS(USER,'T_SHRINK');
-- 查詢計畫可能改善,但 blocks 不變
-- 4. 方案 C:SHRINK SPACE (推薦)
ALTER TABLE t_shrink ENABLE ROW MOVEMENT;
ALTER TABLE t_shrink SHRINK SPACE; -- 或 SHRINK SPACE COMPACT 僅整理不調整 HWM
ALTER TABLE t_shrink DISABLE ROW MOVEMENT;
-- 5. 再次觀察
SELECT blocks, empty_blocks FROM user_tables WHERE table_name='T_SHRINK';
-- blocks 大幅下降,空間歸還表空間
**`SHRINK SPACE` 是 10g+ 版本解決 DELETE 後空間回收的標準答案**:在線、保留物件屬性、真正降 HWM 歸還空間。配合 `COMPACT` 預整理 + 維護窗口正式收縮,可在零停機業務高峰期安全執行。舊版本 9i 僅能走 EXP/DROP/IMP 路徑,需安排停機窗口。