项目组同事在进行海量数据的POC实验,结果发现数据文件增长过快,超过了规划范围。笔者在数据清空之后,要进行文件缩小操作,释放掉占用的空间。
1、 故障现象
首先,我们将数据文件大小约为4G,是自动拓展后的结果。
SQL> select file_name, bytes/1024/1024/1024 from dba_data_files where tablespace_name='NBSMIGIND';
FILE_NAME BYTES/1024/1024/1024
-------------------------------------------------------------------------------- --------------------
/nbstdata04/oradata/NBSTEST/nbsdata/nbsmigind01.dbf 3.91015625
该文件是表空间nbsmigind下的唯一数据文件,其中的对象段空间只有约500M左右。
SQL> select count(*),sum(bytes)/1024/1024 from dba_segments where tablespace_name='NBSMIGIND';
COUNT(*) SUM(BYTES)/1024/1024
---------- --------------------
62 525
那么,现在希望将数据文件缩小到2G左右。我们这种场景通常会使用resize命令完成。
SQL> alter database datafile '/nbstdata04/oradata/NBSTEST/nbsdata/nbsmigind01.dbf' resize 2000m;
alter database datafile '/nbstdata04/oradata/NBSTEST/nbsdata/nbsmigind01.dbf' resize 2000m
ORA-03297: 文件包含在请求的 RESIZE 值以外使用的数据
系统报错ORA-03297。当前段segment所占用的空间明显小于2G,那么为什么不能进行缩减呢?
2、问题分析
首先,我们可以检查一下这个错误号码的含义。
[oracle@bspdev ~]$ oerr ora 03297
03297, 00000, "file contains used data beyond requested RESIZE value"
// *Cause: Some portion of the file in the region to be trimmed is
// currently in use by a database object
// *Action: Drop or move segments containing extents in this region prior to
// resizing the file, or choose a resize value such that only free
// space is in the trimmed.
从含义上看,好象是说存在这样的对象,它的位置大小要超过希望缩小的位置。这个解释,显然不是针对容量而言,因为对象的总容量显然要小于2G空间。
经过研究分析,可以猜到一些端倪。
Oracle的段对象是通过一系列的extents组合而成,每个extent内部是连续的数据block。而各个extent之间的关系是分割的,可能分布在多个文件的多个非连续的位置上。
一个文件中,存在若干个数据块。文件的块号block_id是针对特定的文件而言的。如果一个文件很大,那么其中最大的block_id自然大,反之则小。
调整Oracle对象物理地址的方法,就是将对象的物理位置重新定位整合,到一个新的位置上去。比如,我们在数据表HWM过高的时候,可以使用move或者shrink space命令调节,将数据行重新整合。对索引index对象,我们可以rebuild操作。
Oracle数据文件的resize操作,本质上就是将文件的水位线强制下调,从而释放掉不用的空间。那么,如果在下调过程中,虽然中间有很多空闲位置,但存在对象恰好分配在很高的文件位置上,就会引起ORA-03297错误。因为resize命令没有将段对象移动的效用。
3、问题解决
那么,猜想是否成立呢?我们检查一下表空间nbsmigind中段分区的分配情况,按照block_id进行划分。
SQL> select segment_name, block_id from dba_extents where tablespace_name='NBSMIGIND' order by block_id desc;
SEGMENT_NAME BLOCK_ID
-------------------------------------------------------------------------------- ----------
PK_BSD_TRANS_SEQ_NUMBER 483200
PK_BSD_TRANS_SEQ_NUMBER 465920
PK_BSD_TRANS_SEQ_NUMBER 449536
PK_BSD_TRANS_SEQ_NUMBER 433024
IDX_BSD_TRANS_INC_FILE_SEQ 177408
PK_BSD_TRANS_SEQ_NUMBER 176512
IDX_BSD_TRANS_ERROR_AGTBILLP 93184
PK_BSD_ITRY_SEQ_NUMBER 93056
IDX_BSD_TRANS_ERROR_TRANS_ID 92928
PK_BSD_TRANS_ERROR_SEQ_NUMBER 92800
IDX_BSD_FBOX_TRANS_ID 92672
IDX_BSD_TRANS_ERROR_AGTBILLP 92544
IDX_BSD_TAX_TRANS_ID 92416
IDX_BSD_TRANS_ERROR_INC_FILE 92288
(篇幅原因,有省略…..)
从block_id分布上看,可以发现其中的两三个对象的block_id突然性的增加到176000以上和40000以上。而其他的对象block_id大都只分布在90000以下。那么,是不是因为这些对象的“孤悬海外”引起的故障问题呢?
问题对象主要是索引段,采用rebuild方式暂时将其转移到其他表空间中,再进行处理。
SQL> alter index PK_BSD_TRANS_SEQ_NUMBER rebuild tablespace nbsmigtbl;
Index altered
SQL> alter index IDX_BSD_TRANS_INC_FILE_SEQ rebuild tablespace nbsmigtbl;
Index altered
SQL> alter index PK_BSD_TRANS_SEQ_NUMBER rebuild tablespace nbsmigtbl;
Index altered
此时,再次进行空间调整,结果为:
SQL> alter database datafile '/nbstdata04/oradata/NBSTEST/nbsdata/nbsmigind01.dbf' resize 2000m;
Database altered
调整成功,最后别忘了将转移的对象调回来。
SQL> alter index PK_BSD_TRANS_SEQ_NUMBER rebuild tablespace nbsmigind;
Index altered
SQL> alter index IDX_BSD_TRANS_INC_FILE_SEQ rebuild tablespace nbsmigind;
Index altered
SQL> alter index PK_BSD_TRANS_SEQ_NUMBER rebuild tablespace nbsmigind;
Index altered
为了防止此类事情再次发生,暂时还是关闭自动拓展功能。
SQL> alter database datafile '/nbstdata04/oradata/NBSTEST/nbsdata/nbsmigtbl01.dbf' autoextend off;
Database altered
4、结论
从官方角度,对resize缩小文件的场景,是有其他的标准操作。Oracle是建议先将所有对象转移到一个临时位置上,之后缩小resize文件。最后再将对象转移回原表空间。
笔者实际上就是占了越界对象少的情况,取巧而为。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/17203031/viewspace-712019/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/17203031/viewspace-712019/