在我管的系统中,数据库磁盘经常只剩下20G左右,以前是删除数据库服务器中的日志,日志做了定时清理之后,发现表空间经常出现表空间不足的情况,每次都是通过扩充表空间来解决问题,但是加了几次之后,服务器的磁盘不够用了,就开始清理数据库中的数据。清理了数据之后,发现表空间实际占用率很小,用不到那么多的磁盘,于是想到把用到的磁盘释放出来。
在处理的过程中,发现truncate表只能够减小表空间占用率,并不能释放磁盘通过请教别人,了解到有下面方法可以释放磁盘。
方法一:
查看表空间对应的数据文件大小
select FILE_NAME,FILE_ID,TABLESPACE_NAME,BYTES/1024/1024 mb,BLOCKS from dba_data_files where
TABLESPACE_NAME='TFR_DATA';
查看数据文件中数据处在最大位置
select max(block_id) from dba_extents where file_id=9;
计算表空间实际需要多大空间
select 1354880*8/1024 from dual;
设置表空间大小为该值
ALTER DATABASE DATAFILE '/u01/oradata/FOSSDB/datafile/o1_mf_tfr_data_9ymk9p5n_.dbf' RESIZE 10600M;
这种方法在我之前的文章中写到过。这种方法也是有缺陷的,表空间中实际没有很多数据,例如只有100M数据,但是这种方法resize的时候,发现只能够resize到10G左右,并没有释放出很大的空间。
方法二:
缩小数据文件尺寸报ORA-03297的处理办法
ORA-03297: 文件包含在请求的 RESIZE 值以外使用的数据
最近历史数据库磁盘空间不足,而有一个表空间有50个G容量,但是实际只占100m的空间,
使用ALTER TABLE table SHRINK SPACE CASCAD后大部分数据文件可以调整,当试图调整其中一个数据文件尺寸的时候报
RA-03297: file contains used data beyond requested RESIZE value
说明这个文件不能通过降低hwm来释放空间了。******************************************
数据库版本:oracle 10.2.1
--找到数据文件对应的文件号*********
SQL>select file#,name from v$datafile where name like '%BASEINFO.dbf';
5 /data/eucpdb/eucpdb/BASEINFO.dbf
找到文件中最大的块号
SQL>select max(block_id) from dba_extents where file_id=5 ;************************
1213833
--查看数据库块大小
SQL>show parameter db_block_size
db_block_size integer 8192
计算一下文件中最大使用块占用的位置
SQL>select 1213833*8/1024 from dual;
9483.0703125 M
--为了验证上面做法的准确性,下面做一个试验
--调整前数据文件大小为10000M
--现在调整数据库文件为9500M
SQL>ALTER DATABASE DATAFILE '/data/eucpdb/eucpdb/BASEINFO.dbf' RESIZE 9500M
2 /
数据库已更改
--调整文件为 9400m
SQL>ALTER DATABASE DATAFILE '/data/eucpdb/eucpdb/BASEINFO.dbf' RESIZE 9400M
2 /
SQL> ALTER DATABASE DATAFILE '/data/eucpdb/eucpdb/BASEINFO.dbf' RESIZE 9400M;
ALTER DATABASE DATAFILE '/data/eucpdb/eucpdb/BASEINFO.dbf' RESIZE 9400M
*
第 1 行出现错误:
ORA-03297: 文件包含在请求的 RESIZE 值以外使用的数据
--看来了上面的计算是准确的
解决方法
查看表空间中有哪些对象
select * from DBA_SEGMENTS where TABLESPACE_NAME='BASEINFO';
select * from DBA_tables;
select FILE_NAME,FILE_ID,TABLESPACE_NAME,BYTES/1024/1024 mb,BLOCKS from dba_data_files where
TABLESPACE_NAME='TFR_DATA';
查看FILE_ID
SQL> select segment_name,segment_type,tablespace_name,extent_id,bytes,blocks from dba_extents where file_id=5 and block_id='1213833';
SEGMENT_NAME SEGMENT_TYPE TABLESPACE_NAME EXTENT_ID BYTES BLOCKS
------------------------------ ------------------ ------------------------------ ---------- ---------- ----------
REGISTRYINFO TABLE BASEINFO 25 524288 64
SQL>
SQL> ALTER TABLE eucpmanager.REGISTRYINFO SHRINK SPACE CASCADE;
表已更改。
创建一个新的表空间,把block_id比较高的几个表移出表空间
SQL> CREATE SMALLFILE TABLESPACE "BASEINFO_BAK" DATAFILE '/data/eucpdb/eucpdb/baseinfo_bak.dbf' SIZE 100M LOGGING EXTENT MANAGEMENT LOCAL SEGMENT SPACE MANAGEMENT AUTO
2 /
表空间已创建。
SQL> alter user eucpmanager quota unlimited on BASEINFO_BAK;
用户已更改。使得数据库中表的所属用户能够操作新建的表空间。否则不能把表移到新的表空间中
把block_id比较高的几个表移动到新的表空间
SELECT DISTINCT SEGMENT_NAME FROM DBA_EXTENTS WHERE TABLESPACE_NAME='BASEINFO' AND FILE_ID=5 and segment_type='TABLE' ;
SQL> SELECT distinct 'alter table '|| SEGMENT_NAME||' move tablespace baseinfo_bak; ' FROM DBA_EXTENTS WHERE TABLESPACE_NAME='BASEINFO' AND FILE_ID=5 and segment_type='TABLE' ;
'ALTERTABLE'||SEGMENT_NAME||'MOVETABLESPACEBASEINFO_BAK;'
----------------------------------------------------------------------------------------------------------------------------
alter table ENTERPRISESERVICEINFO move tablespace baseinfo_bak;
alter table REGISTRYFEEDETAILEX move tablespace baseinfo_bak;
alter table ENTERPRISEROUTE move tablespace baseinfo_bak;
alter table REGISTRYAUTHINFO move tablespace baseinfo_bak;
alter table ENTERPRISEBASEINFO move tablespace baseinfo_bak;
SQL> alter table ENTERPRISESERVICEINFO move tablespace baseinfo_bak;
alter table REGISTRYFEEDETAILEX move tablespace baseinfo_bak;
alter table ENTERPRISEROUTE move tablespace baseinfo_bak;
alter table REGISTRYAUTHINFO move tablespace baseinfo_bak;
alter table ENTERPRISEBASEINFO move tablespace baseinfo_bak;
表已更改。
SQL>
表已更改。
SQL>
表已更改。
SQL>
表已更改。
告警日志中会出现下面的内容,索引需要重建
Thu Apr 24 14:20:21 2008
Some indexes or index [sub]partitions of table EUCPMANAGER.ENTERPRISEBASEINFO have been marked unusable
把下面的执行结果的语句执行所有重建
SELECT distinct 'alter INDEX '|| SEGMENT_NAME||' REBUILD TABLESPACE BASEINFO_BAK; ' FROM DBA_EXTENTS WHERE TABLESPACE_NAME='BASEINFO' AND FILE_ID=5 and segment_type='INDEX' ;
alter INDEX PK_ENTERPRISEBASEINFO REBUILD TABLESPACE BASEINFO_BAK;
alter INDEX PK_REGISTRYINFO REBUILD TABLESPACE BASEINFO_BAK;
alter INDEX PK_REGISTRYFEEDETAILEX REBUILD TABLESPACE BASEINFO_BAK;
alter INDEX UNI_REGISTRYAUTHINFO REBUILD TABLESPACE BASEINFO_BAK;
alter INDEX UNI_REGISTRYAUTHINFO REBUILD TABLESPACE BASEINFO_BAK;
alter INDEX UNI_REGISTRYAUTHINFO REBUILD TABLESPACE BASEINFO_BAK;
alter INDEX UNI_REGISTRYAUTHINFO REBUILD TABLESPACE BASEINFO_BAK;
alter INDEX UNI_REGISTRYAUTHINFO REBUILD TABLESPACE BASEINFO_BAK;
再次修改数据文件大小
SQL> select max(block_id) from dba_extents where file_id=5 ;
MAX(BLOCK_ID)
-------------
3209
SQL> ALTER DATABASE DATAFILE '/data/eucpdb/eucpdb/BASEINFO.dbf' RESIZE 1000m;
数据库已更改。
数据库文件的空间已经调整成功了
SQL>
--把挪走的表在挪回来
SQL> alter table ENTERPRISESERVICEINFO move tablespace baseinfo;
alter table REGISTRYFEEDETAILEX move tablespace baseinfo;
alter table ENTERPRISEROUTE move tablespace baseinfo;
alter table REGISTRYAUTHINFO move tablespace baseinfo;
alter table ENTERPRISEBASEINFO move tablespace baseinfo;
alter table registryinfo move tablespace baseinfo;
表已更改。
SQL>
表已更改。
--重建索引
SQL>
SQL>
SQL> ALTER INDEX PK_REGISTRYINFO REBUILD TABLESPACE BASEINFO;
ALTER INDEX AK_REGISTRYCODE_REGISTRYINFO REBUILD TABLESPACE BASEINFO;
ALTER INDEX PK_ENTERPRISEBASEINFO REBUILD TABLESPACE BASEINFO;
ALTER INDEX PK_ENTERPRISESERVICEINFO REBUILD TABLESPACE BASEINFO;
ALTER INDEX UNI_REGISTRYAUTHINFO REBUILD TABLESPACE BASEINFO;
ALTER INDEX PK_REGISTRYFEEDETAILEX REBUILD TABLESPACE BASEINFO;
索引已更改。
SQL> SELECT COUNT(*) FROM DBA_SEGMENTS WHERE TABLESPACE_NAME='BASEINFO_BAK' ;
COUNT(*)
----------
0
已经没有对象在新建的这个表空间了。现在删除掉
SQL> drop tablespace baseinfo_bak;
表空间已删除。
但是,在操作的过程中,出现一个非常难搞的问题,
SELECT COUNT(*) FROM DBA_EXTENDS WHERE TABLESPACE_NAME='USERS' ;
COUNT(*)
----------
0
select max(block_id) from dba_extents where file_id=9;
这样查看也是什么都没有,但是resize的时候就是报错,ORA-03297: 文件包含在请求的 RESIZE 值以外使用的数据。
处理方法:
SQL> SELECT COUNT(*) FROM DBA_SEGMENTS WHERE TABLESPACE_NAME='USERS' ;
这里要查看DBA_SEGMENTS,DBA_TABLES,DBA_INDEX这几个表,DBA_EXTENTS太小了,不全面,查看的时候发现数据虽然删除了,但是保留在了回收站中,要在PLSQL命令窗口执行如下命令 purge dba_recyclebin.执行后就能够resize了。
这是绝对百度不到的,问别人也不好想到这里。还是要经验呀。
这样查看表空间中的对象为0,
到此调整已经结束了。
其实调整方法有很多,如用imp/exp等
异常处理
查看一个表属于哪个用户
select owner from dba_tables where table_name='表名';
SQL> create tablespace wulili datafile '/u01/app/oracle/oradata/dpweb/wulili.dbf' size 1024M autoextend on;
create tablespace wulili datafile '/u01/app/oracle/oradata/dpweb/wulili.dbf' size 1024M autoextend on
ERROR at line 1:
ORA-01119: error in creating database file '/u01/app/oracle/oradata/dpweb/wulili.dbf'
ORA-27040: file create error, unable to create file
Linux-x86_64 Error: 2: No such file or directory
Additional information: 1
solution:give exact path of datafile inplace of $ORACLE_HOME.
like
Create Tablespace CLOUD_DATA datafile '/u01/app/oradata/cloud_data01.dbf' size 1000M
SQL> alter table tb_auto shrink space;
alter table tb_auto shrink space
*
第 1 行出现错误:
ORA-10636: ROW MOVEMENT is not enabled
SQL> alter table tb_auto enable row movement;
本文转自aaa超超aaa 51CTO博客,原文链接:http://blog.51cto.com/10983441/1791131