小伙伴們有沒有經歷過,超大表和超大數據的導入后,數據被刪除了,然而空間遲遲不釋放,存儲添置又跟不上,業務空間告警的時候。收縮就很必須了,然而收縮需謹慎,數據大過天。DBMS_SPACE.SHRINK_TABLESPACE是Oracle 23ai新增功能,使得23 ai有了在線一鍵shrink tablespace的功能,19c及以下還需要手動操作。
一、Shrink技術特性
在Oracle 23ai中,? 大文件表空間收縮(Shrink Tablespace)?? 的核心機制是通過數據重組消除存儲碎片,關鍵技術點如下:
-
?空間碎片整理?
當表被截斷(TRUNCATE)或數據刪除后,數據文件中會產生不連續的空白空間間隙(GAP)?。收縮操作通過移動段對象將這些碎片整理到文件末尾。
-
在線段重組?
使用DBMS_SPACE.SHRINK_TABLESPACE時:
- 自動識別可移動對象(表、索引等)
- 在線移動段數據(支持DML并發)
- 強制模式(TS_MODE_SHRINK_FORCE)處理不支持在線移動的對象
-
?文件截斷機制?
碎片整理完成后,Oracle將空白空間從文件尾部截斷,實現物理文件收縮。
-
操作模式?
- ?分析模式(TS_MODE_ANALYZE)??:計算可回收空間
該模式不會實際移動數據或回收空間,而是分析表空間并返回一個報告,顯示可以回收多少空間,以及建議的目標數據文件大小。它只是模擬收縮操作,不會對數據文件做任何修改。
- ?收縮模式(TS_MODE_SHRINK)??:執行實際空間回收
該模式會實際執行空間回收操作。它將移動表空間中可移動的段(如普通表、索引等),以壓縮數據文件中的空間,然后截斷數據文件以釋放未使用的空間。
- TS_TARGET_MAX_SHRINK:盡可能多地回收空間(默認)
指定一個具體的數值(以字節為單位)作為目標大小。
- 強制模式(TS_MODE_SHRINK_FORCE),
它會嘗試移動那些在普通收縮模式下無法移動的段(通過離線移動等方式)。該模式會嘗試對普通模式下無法移動的對象進行離線移動(Offline Move)。這可能會導致相關對象在移動期間不可用,因此使用時要謹慎。
可被移動對方回收空間:
- 普通堆表(Heap Table)
- 索引組織表(IOT)
- 索引(Index)
- 分區表的分區(Partition)
- 物化視圖(Materialized View)
- 物化視圖日志(Materialized View Log)
不可移動對象?:
某些對象不能被移動,例如:
- 包含LOB列且LOB存儲在單獨段中的表(因為LOB段可能位于不同的表空間)
- 具有活動事務的對象
- 包含LONG類型的表
- 系統表空間(SYSTEM, SYSAUX)中的對象(盡管SYSAUX可以收縮,但有特殊限制)
空間回收限制?:即使使用強制模式,仍然可能無法回收所有空間,
- 表空間中的某些對象無法移動(如上述不可移動對象)
- 數據文件中的某些空間是正在使用的,無法回收
性能影響?:
收縮操作會移動數據,因此會消耗I/O資源。建議在業務低峰期進行。
依賴關系?:
如果表空間中的對象有依賴關系(例如表上的索引),收縮操作會自動按正確順序處理這些對象。
二、典型使用場景
- ?批量數據清理后? - 截斷/刪除大表后回收空間
- ?存儲空間優化? - 解決文件系統空間不足問題
- ?數據歸檔場景? - 歷史數據遷移后回收空間
- ?周期性維護? - 作為數據庫健康檢查的一部分
?三、Oracle 23ai 實操腳本
-- 1. 創建測試環境
ALTER SYSTEM SET db_create_file_dest='/opt/oracle/oradata/FREE';
--System altered.DROP USER IF EXISTS shrink_user CASCADE;
--User SHRINK_USER dropped.DROP TABLESPACE IF EXISTS shrink_ts INCLUDING CONTENTS AND DATAFILES;
--TABLESPACE SHRINK_TS dropped.CREATE BIGFILE TABLESPACE shrink_ts DATAFILE SIZE 10M AUTOEXTEND ON NEXT 1M;
--TABLESPACE SHRINK_TS created.CREATE USER shrink_user IDENTIFIED BY shrink_userDEFAULT TABLESPACE shrink_tsQUOTA UNLIMITED ON shrink_ts;
--User SHRINK_USER created.GRANT CREATE SESSION, CREATE TABLE TO shrink_user;
GRANT SELECT_CATALOG_ROLE TO shrink_user;
--Grant succeeded.-- 2. 創建測試數據
sqlplus shrink_user/shrink_user@localhost:1521/FREEPDB1
--
[oracle@OL97 customer_orders]$ sqlplus shrink_user/shrink_user@localhost:1521/FREEPDB1
SQL*Plus: Release 23.0.0.0.0 - Production on Sun Jun 15 13:38:32 2025
Version 23.8.0.25.04
Copyright (c) 1982, 2025, Oracle. All rights reserved.
Connected to:
Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free
Version 23.8.0.25.04
SHRINK_USER@localhost:1521/FREEPDB1>
--
CREATE TABLE sales_data (id NUMBER,details VARCHAR2(4000),CONSTRAINT sales_pk PRIMARY KEY (id)
);
--Table created.INSERT /*+APPEND*/ INTO sales_data
SELECT ROWNUM, RPAD('X', 4000, 'X')
FROM dual
CONNECT BY LEVEL <= 100000;
COMMIT;
--
100000 rows created.
SHRINK_USER@localhost:1521/FREEPDB1>
Commit complete.
--收集信息
EXEC DBMS_STATS.GATHER_TABLE_STATS(null, 'SALES_DATA');
SHRINK_USER@localhost:1521/FREEPDB1> EXEC DBMS_STATS.GATHER_TABLE_STATS(null, 'SALES_DATA');
PL/SQL procedure successfully completed.-- 3. 檢查初始空間分配
SELECT tablespace_name, ROUND(bytes/1024/1024, 2) AS size_mb
FROM dba_data_files
WHERE tablespace_name = 'SHRINK_TS';
--
TABLESPACE_NAME SIZE_MB
------------------------------ ----------
SHRINK_TS 908
--
SELECT table_name, blocks,ROUND((blocks*8)/1024, 2) AS size_mb
FROM user_tables;
--
TABLE_NAME BLOCKS SIZE_MB
_____________ _________ __________
SALES_DATA 100507 785.21-- 4. 刪表模擬數據清理
TRUNCATE TABLE sales_data;
EXEC DBMS_STATS.GATHER_TABLE_STATS(null, 'SALES_DATA');
-- 刪除也可以模擬 模擬空間碎片
DELETE FROM SALES_DATA WHERE id <= 40000;
COMMIT;
--
SHRINK_USER@localhost:1521/FREEPDB1> DELETE FROM SALES_DATA WHERE id <= 40000;
40,000 rows deleted.
-- 5. 分析可回收空間 (SYS權限)
sqlplus / AS SYSDBA
SET SERVEROUTPUT ONBEGINDBMS_SPACE.SHRINK_TABLESPACE(tablespace_name => 'SHRINK_TS',shrink_mode => DBMS_SPACE.TS_MODE_ANALYZE);
END;
/---- 5. 預收縮空間分析
SELECT segment_name,segment_type,blocks,bytes/1024/1024 size_mb
FROM user_segments;
--
SEGMENT_NAME SEGMENT_TYPE BLOCKS SIZE_MB
_______________ _______________ _________ __________
SALES_DATA TABLE 101248 791
SALES_PK INDEX 256 2-- 6. 執行空間收縮(SYS權限)
BEGINDBMS_SPACE.SHRINK_TABLESPACE('SHRINK_TS');
END;
/
--
[root@OL97 dbs]# su - oracle
[oracle@OL97 ~]$ sql / as sysdba;
SQLcl: Release 25.1 Production on Sun Jun 15 13:43:44 2025
Copyright (c) 1982, 2025, Oracle. All rights reserved.
Connected to:
Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free
Version 23.8.0.25.04
SYS@CDB$ROOT> alter session set container =FREEPDB1;
Session altered.
SYS@CDB$ROOT> BEGIN2 DBMS_SPACE.SHRINK_TABLESPACE('SHRINK_TS');3 END;4* /PL/SQL procedure successfully completed.
SYS@CDB$ROOT>-- 7. 驗證收縮結果
SELECT tablespace_name, ROUND(bytes/1024/1024, 2) AS size_mb
FROM dba_data_files
WHERE tablespace_name = 'SHRINK_TS';
--
TABLESPACE_NAME SIZE_MB
__________________ __________
SHRINK_TS 862-- 清理環境
DROP USER shrink_user CASCADE;
DROP TABLESPACE shrink_ts INCLUDING CONTENTS AND DATAFILES;
四、驗證要點?
- 空間回收驗證
-- 收縮前后空間對比
SELECT df.tablespace_name,SUM(df.bytes)/1024/1024 allocated_mb,SUM(df.bytes - NVL(fs.free_bytes, 0))/1024/1024 used_mb
FROM dba_data_files df
LEFT JOIN (SELECT file_id, SUM(bytes) AS free_bytes -- 添加明確別名FROM dba_free_spaceGROUP BY file_id
) fs ON df.file_id = fs.file_id
WHERE df.tablespace_name = 'SHRINK_TS' -- 添加表別名
GROUP BY df.tablespace_name; -- 添加表別名
--
TABLESPACE_NAME ALLOCATED_MB USED_MB
__________________ _______________ ___________
SHRINK_TS 862 861.0625
- 段移動監控??
-- 實時監控收縮操作
SELECT sql_id,sid,event,p1 TEXT,p2 BLOCKS_MOVED
FROM v$session
WHERE module = 'SHRINK_TBS';
- 查詢依賴驗證??
-- 檢查未收縮對象
SELECT segment_name, segment_type
FROM dba_segments
WHERE tablespace_name = 'SHRINK_TS'AND blocks > 0
MINUS
SELECT segment_name, segment_type
FROM dba_segments
WHERE tablespace_name = 'SHRINK_TS'AND blocks > 0AND segment_name IN (SELECT object_name FROM dba_objectsWHERE created < SYSDATE - 1/24
);
--
SEGMENT_NAME SEGMENT_TYPE
_______________ _______________
SALES_DATA TABLE
SALES_PK INDEX
五、關鍵注意事項
- ?在線操作限制?標準模式僅處理支持在線移動的對象,強制模式可能導致短暫鎖表
- ?空間預留策略?ALTER TABLESPACE ... AUTOEXTEND OFF 可在收縮前禁用自動擴展
- ?系統表空間支持?SYSAUX表空間可收縮,但SYSTEM表空間不支持
- ?操作監控?通過?V$SESSION_LONGOPS 監控收縮進度:
SELECT sid, serial#, opname, sofar, totalwork
FROM v$session_longops
WHERE opname LIKE 'SHRINK%';
- ?最佳操作時間?
- - 在業務低峰期執行
- - 收縮前進行完整備份
- - 優先使用分析模式評估收益
?Oracle 23ai的大文件表空間收縮技術徹底解決了傳統表空間空間回收需依賴操作系統的問題,結合OMF(Oracle Managed Files)特性,實現了端到端的自動化存儲管理。通過在線重組實現存儲空間的高效回收,顯著降低存儲成本。