
DBMS_SPACE 包对 大文件表空间(Bigfile Tablespace)进行收缩以回收未使用空间,还能在 23.7 版本之后,对小文件表空间(Smallfile Tablespace)执行同样的空间回收操作。这意味着数据库管理员在面对长期运行、频繁删除或重建表数据的环境中,能更灵活、更高效地优化存储资源。
在数据库长时间运行过程中,随着表、索引的反复创建与删除,数据文件中会产生大量未使用的“空洞”。 这些空间虽然被标记为空闲,但在物理层面上仍然占用磁盘。 而过去,Oracle 提供的表空间收缩能力主要集中在 大文件表空间,对于小文件表空间的空间回收并不支持。
从 Oracle 23ai 23.7 起,DBMS_SPACE 包的 SHRINK_TABLESPACE 过程新增了对小文件表空间的支持,使得我们可以更精细地管理多数据文件表空间的空间使用情况。
下面我们通过一个完整的实验演示来验证这一新特性。 实验环境为 Oracle 23ai(23.7 版本及以上),连接方式如下:
conn sys/Oracle1@//localhost:1521/pdb1 as sysdba在 Oracle 23ai 中,默认创建的是大文件表空间(bigfile)。 因此我们在测试时,需要显式指定创建 smallfile 表空间,并包含多个数据文件。
-- 创建一个包含多个数据文件的表空间
drop user if exists test_user cascade;
drop tablespace if exists test_ts including contents and datafiles;
create smallfile tablespace test_ts datafile
size 10m autoextend on next 1m,
size 10m autoextend on next 1m,
size 10m autoextend on next 1m,
size 10m autoextend on next 1m;
2. 创建测试用户及授权
-- 创建测试用户并授权
drop user if exists test_user cascade;
create user test_user identified by test_user default tablespace test_ts quota unlimited on test_ts;
grant create session, create table to test_user;
grant select_catalog_role to test_user;我们在测试用户下创建两张表 t1 和 t2,插入大量数据以模拟真实使用场景:
-- 在测试用户下创建两张表并插入测试数据
conn test_user/test_user@//localhost:1521/pdb1
create table t1 (
id number,
col1 varchar2(4000),
col2 varchar2(4000),
constraint t1_pk primary key (id)
);
create table t2 (
id number,
col1 varchar2(4000),
col2 varchar2(4000),
constraint t2_pk primary key (id)
);
insert /*+append*/ into t1
select rownum, rpad('x', 4000, 'x'), rpad('x', 4000, 'x')
from dual
connect by level <= 100000;
commit;
insert /*+append*/ into t2
select rownum, rpad('x', 4000, 'x'), rpad('x', 4000, 'x')
from dual
connect by level <= 100000;
commit;
exec dbms_stats.gather_table_stats(null, 't1');
exec dbms_stats.gather_table_stats(null, 't2');我们先查看表空间的数据文件大小及每张表的占用情况:
column file_name format a30
select substr(file_name, -28) as file_name, blocks, bytes/1024/1024 as size_mb
from dba_data_files
where tablespace_name = 'TEST_TS';
FILE_NAME BLOCKS SIZE_MB
------------------------------ ---------- ----------
o1_mf_test__mtmskcv6_.dbf 124928 976
o1_mf_test__mtmskcvd_.dbf 109312 854
o1_mf_test__mtmskcvl_.dbf 98048 766
o1_mf_test__mtmskcvr_.dbf 98944 773
SQL>
column table_name format a10
select table_name, blocks, (blocks*8)/1024 as size_mb
from user_tables
where table_name in ('T1', 'T2')
order by 1;
TABLE_NAME BLOCKS SIZE_MB
---------- ---------- ----------
T1 200692 1567.90625
T2 200692 1567.90625执行后可看到每个数据文件和表对象的空间占用情况。 此时表空间已被两张大表占满。
我们清空表 t1,使其腾出大量未使用空间。
truncate table t1;
exec dbms_stats.gather_table_stats(null, 't1');接着运行分析模式的收缩操作,查看通过 DBMS_SPACE 可回收的空间量:
conn sys/Oracle1@//localhost:1521/pdb1 as sysdba
set serveroutput on
execute dbms_space.shrink_tablespace('TEST_TS', shrink_mode => dbms_space.ts_mode_analyze);
输出结果如下:
-------------------ANALYZE RESULT-------------------
Total Movable Objects: 2
Total Movable Size(GB): .37
Original Datafile Size(GB): 3.29
Suggested Target Size(GB): 1.94
Process Time: +00 00:00:02.036832
PL/SQL procedure successfully completed.
这说明系统检测到约 0.37GB 的可移动数据块,表空间理论上可收缩至约 1.94GB。
执行真正的收缩动作以回收空间:
set serveroutput on
execute dbms_space.shrink_tablespace('TEST_TS');
执行结果:
-------------------SHRINK RESULT-------------------
Total Moved Objects: 2
Total Moved Size(GB): .37
Original Datafile Size(GB): 3.29
New Datafile Size(GB): 2.76
Process Time: +00 00:00:52.268145
PL/SQL procedure successfully completed.可见在第一次执行后,表空间成功回收了部分空间。
我们可以继续执行收缩操作,多次运行以进一步压缩和合并数据文件:
set serveroutput on
execute dbms_space.shrink_tablespace('TEST_TS', shrink_mode => dbms_space.ts_mode_shrink, target_size => dbms_space.ts_target_max_shrink);多次执行后,可观察到数据文件数量逐渐减少,最终压缩为一个数据文件:
column file_name format a30
select substr(file_name, -28) as file_name, blocks, bytes/1024/1024 as size_mb
from dba_data_files
where tablespace_name = 'TEST_TS';
FILE_NAME BLOCKS SIZE_MB
------------------------------ ---------- ----------
o1_mf_test__mtmskcv6_.dbf 382080 2985
SQL>TS_MODE_SHRINK_FORCE,这些对象将离线移动。
若业务对可用性要求高,请谨慎使用该模式。通过实验,验证了 Oracle 23ai (23.7) 新增的小文件表空间收缩能力。
借助 DBMS_SPACE.SHRINK_TABLESPACE,数据库管理员可以更灵活地进行空间回收与优化,减少存储浪费,提高数据文件管理的可控性。
在生产环境中,这一功能对于包含多个数据文件、频繁删除数据或历史归档的场景尤其有价值。 合理使用此特性,能有效降低存储成本,保持数据库空间结构的健康与整洁。