首先,可以通过下面的sql statement来查看表空间的使用情况。注意,该语句是在10g下测试过。
SELECT FREE.TABLESPACE_NAME, FREE.FREE_SPACE/TOTAL.TOTAL_SPACE FROM (select TABLESPACE_NAME,sum(bytes)/1024/1024 AS FREE_SPACE from dba_free_space group by TABLESPACE_NAME) FREE, (select TABLESPACE_NAME,sum(BYTES)/1024/1024 AS TOTAL_SPACE from dba_data_files group by TABLESPACE_NAME) TOTAL WHERE FREE.TABLESPACE_NAME=TOTAL.TABLESPACE_NAME;
在知道了表空间的使用情况后,我们可能希望对一些表空间做清理,使其datafile的尺寸变小。这时我们的做法是清理掉一些比较大的表,然后用resize命令来减小datafile的大小。
比如
truncate table scott.big;
alter database datafile '/opt/oradata/orcl/user.dbf' resize 10M;
但是有时你会遇到下面的这种情况。
ERROR at line 1: ORA-03297: file contains used data beyond requested RESIZE value
这个错误看起来像是说你的datafile中没有足够的空间释放,但其实未必。下面通过实验来了解这个错误。
请耐心看完实验过程。
首先创建表空间和用户
SQL> CREATE TABLESPACE reclaim_ts DATAFILE '/opt/oratop/oradata/c21upg10/reclaim_ts01.dbf' SIZE 1M AUTOEXTEND ON NEXT 1M; Tablespace created. SQL> CREATE USER reclaim_user IDENTIFIED BY reclaim_user DEFAULT TABLESPACE reclaim_ts QUOTA UNLIMITED ON reclaim_ts; User created. SQL> GRANT CREATE SESSION, CREATE TABLE TO reclaim_user; Grant succeeded. SQL> GRANT select on dba_objects to reclaim_user; Grant succeeded.
然后创建表t1
SQL> CONN reclaim_user/reclaim_user Connected. SQL> create table t1 as select * from dba_objects; Table created.
创建完表后我们用sys登陆查看一下表空间中 extent的情况。
SQL> SELECT segment_type, segment_name , FILE_ID, BLOCK_ID,blocks,BYTES/1024/1024 from dba_extents WHERE owner = 'RECLAIM_USER' order by block_id; SEGMENT_TYPE SEGMENT_NAME FILE_ID BLOCK_ID BLOCKS BYTES/1024/1024 ------------------------------------------------------ ---------------------------- ---------- ---------- ---------- --------------- TABLE T1 54 9 8 .0625 TABLE T1 54 17 8 .0625 TABLE T1 54 25 8 .0625 TABLE T1 54 33 8 .0625 TABLE T1 54 41 8 .0625 TABLE T1 54 49 8 .0625 TABLE T1 54 57 8 .0625 TABLE T1 54 65 8 .0625 TABLE T1 54 73 8 .0625 TABLE T1 54 81 8 .0625 TABLE T1 54 89 8 .0625 TABLE T1 54 97 8 .0625 TABLE T1 54 105 8 .0625 TABLE T1 54 113 8 .0625 TABLE T1 54 121 8 .0625 TABLE T1 54 129 8 .0625 TABLE T1 54 137 128 1 TABLE T1 54 265 128 1 TABLE T1 54 393 128 1 TABLE T1 54 521 128 1 TABLE T1 54 649 128 1 TABLE T1 54 777 128 1
看到从block 9 开始 到 block 777 这一部分连续的block是t1占用的。 之前的8个block应该是datafile自己占用的。
然后我们再创建一个表t2,该表和t1一样 都是从dba_objects创建
SQL> create table t2 as select * from dba_objects; Table created.
OK, 创建完毕后用sys登陆一个session 把datafile 改成 autoextend off。
SQL> alter database datafile '/opt/oratop/oradata/c21upg10/reclaim_ts01.dbf' AUTOEXTEND off; Database altered.
这时候再去查看一下extent的使用情况
SQL> SELECT segment_type, segment_name , FILE_ID, BLOCK_ID,blocks,BYTES/1024/1024 from dba_extents WHERE owner = 'RECLAIM_USER' order by block_id; SEGMENT_TYPE SEGMENT_NAME FILE_ID BLOCK_ID BLOCKS BYTES/1024/1024 ------------------------------------------------------ ---------------------------- ---------- ---------- ---------- --------------- TABLE T1 54 9 8 .0625 TABLE T1 54 17 8 .0625 TABLE T1 54 25 8 .0625 TABLE T1 54 33 8 .0625 TABLE T1 54 41 8 .0625 TABLE T1 54 49 8 .0625 TABLE T1 54 57 8 .0625 TABLE T1 54 65 8 .0625 TABLE T1 54 73 8 .0625 TABLE T1 54 81 8 .0625 TABLE T1 54 89 8 .0625 TABLE T1 54 97 8 .0625 TABLE T1 54 105 8 .0625 TABLE T1 54 113 8 .0625 TABLE T1 54 121 8 .0625 TABLE T1 54 129 8 .0625 TABLE T1 54 137 128 1 TABLE T1 54 265 128 1 TABLE T1 54 393 128 1 TABLE T1 54 521 128 1 TABLE T1 54 649 128 1 TABLE T1 54 777 128 1 TABLE T2 54 905 8 .0625 TABLE T2 54 913 8 .0625 TABLE T2 54 921 8 .0625 TABLE T2 54 929 8 .0625 TABLE T2 54 937 8 .0625 TABLE T2 54 945 8 .0625 TABLE T2 54 953 8 .0625 TABLE T2 54 961 8 .0625 TABLE T2 54 969 8 .0625 TABLE T2 54 977 8 .0625 TABLE T2 54 985 8 .0625 TABLE T2 54 993 8 .0625 TABLE T2 54 1001 8 .0625 TABLE T2 54 1009 8 .0625 TABLE T2 54 1017 8 .0625 TABLE T2 54 1025 8 .0625 TABLE T2 54 1033 128 1 TABLE T2 54 1161 128 1 TABLE T2 54 1289 128 1 TABLE T2 54 1417 128 1 TABLE T2 54 1545 128 1 TABLE T2 54 1673 128 1
紧跟着T1的extent,从block 905开始到1673 是T2占用的。要注意T1在datafile中是排在T2的前面的。两个 表都占用896个block。出去segment就是888个block。
我们看一下现在datafile 的大小
myserver[/export/home/oratop ] du -sh /opt/oratop/oradata/c21upg10/reclaim_ts01.dbf 15M /opt/oratop/oradata/c21upg10/reclaim_ts01.dbf
现在我们把T1 truncate掉,然后再看该数据文件中extent的使用情况
SQL> conn reclaim_user/reclaim_user Connected. SQL> truncate table t1; Table truncated.
SQL> SELECT segment_type, segment_name , FILE_ID, BLOCK_ID,blocks,BYTES/1024/1024 from dba_extents WHERE owner = 'RECLAIM_USER' order by block_id; SEGMENT_TYPE SEGMENT_NAME FILE_ID BLOCK_ID BLOCKS BYTES/1024/1024 ------------------------------------------------------ ---------------------------- ---------- ---------- ---------- --------------- TABLE T1 54 9 8 .0625 TABLE T2 54 905 8 .0625 TABLE T2 54 913 8 .0625 TABLE T2 54 921 8 .0625 TABLE T2 54 929 8 .0625 TABLE T2 54 937 8 .0625 TABLE T2 54 945 8 .0625 TABLE T2 54 953 8 .0625 TABLE T2 54 961 8 .0625 TABLE T2 54 969 8 .0625 TABLE T2 54 977 8 .0625 TABLE T2 54 985 8 .0625 TABLE T2 54 993 8 .0625 TABLE T2 54 1001 8 .0625 TABLE T2 54 1009 8 .0625 TABLE T2 54 1017 8 .0625 TABLE T2 54 1025 8 .0625 TABLE T2 54 1033 128 1 TABLE T2 54 1161 128 1 TABLE T2 54 1289 128 1 TABLE T2 54 1417 128 1 TABLE T2 54 1545 128 1 TABLE T2 54 1673 128 1
可以看到T1除了一个 一个segment header不再占用block。 查看dba_free_space也可以看到
SQL> select BLOCK_ID,BLOCKS,BYTES/1024/1024 from dba_free_space where file_id=54; BLOCK_ID BLOCKS BYTES/1024/1024 ---------- ---------- --------------- 17 888 6.9375 1801 120 .9375
这个视图的第一个free空间从第17个block开始共888个block。这是t1 truncate释放掉的,共6.9M。
第二个free空间从1801开始用120个block,这是T2到datafile的结尾处的空闲部分。
ok, 既然现在T1释放了6.9M, 结尾处还有接近0.9M的空间,那么我把文件缩小6m 也就是缩小到 15-6=9M 不过分吧?
我们试一下
SQL> alter database datafile '/opt/oratop/oradata/c21upg10/reclaim_ts01.dbf' resize 9m; alter database datafile '/opt/oratop/oradata/c21upg10/reclaim_ts01.dbf' resize 9m * ERROR at line 1: ORA-03297: file contains used data beyond requested RESIZE value
有错误,显示不行。 resize这个选项只能把datafile中最后一部分free space释放出来。 向T1的这部分free space 因为是在中间,所以没办法释放。但是如果是后面的这0.9M,我们就可以释放掉。
SQL> SELECT 14.1*1024 FROM DUAL; 14.1*1024 ---------- 14438.4 SQL> alter database datafile '/opt/oratop/oradata/c21upg10/reclaim_ts01.dbf' resize 14439K; Database altered.
那么,这种情况我们怎么处理呢?
两种方法
1. 创建新的表空间
2. move segment到新的表空间
3. drop原来的表空间
4. rename新的表空间使其名字和原来相同
让我们试试。
创建表空间
SQL> create tablespace test DATAFILE '/opt/oratop/oradata/c21upg10/reclaim_ts_01_reorganize.dbf' size 1m autoextend on next 1m; Tablespace created.
给用户赋权让用户可以在新的表空间创建表
SQL> alter user reclaim_user default tablespace test; User altered. SQL> grant unlimited tablespace to reclaim_user; Grant succeeded.
移动原来的表
SQL> alter table reclaim_user.t1 move tablespace test; Table altered. SQL> alter table reclaim_user.t2 move tablespace test; Table altered.
删掉原来的表空间
SQL> DROP TABLESPACE reclaim_ts INCLUDING CONTENTS AND DATAFILES; Tablespace dropped.
重命名表空间并修改datafile
SQL> alter tablespace test rename to reclaim_ts; Tablespace altered. SQL> alter database datafile '/opt/oratop/oradata/c21upg10/reclaim_ts_01_reorganize.dbf' autoextend off; Database altered.
查看数据文件大小
myserver[/export/home/oratop ] du -sh /opt/oratop/oradata/c21upg10/reclaim_ts_01_reorganize.dbf 9.0M /opt/oratop/oradata/c21upg10/reclaim_ts_01_reorganize.dbf