最近在开发环境使用的服务器上,发现磁盘空间占满,主要是数据库文件占用的磁盘空间太大,F盘大小为100G,数据库文件就整整占用了99G,在该服务器上数据库文件有两个实例,一个为A占用了55G,一个为B占用了44G()。
A实例:
****_INDX.DBF |
3G |
****_DATA.DBF |
16.8G |
****_DATA01.DBF |
16.8G |
t_INDX.DBF |
512M |
t_DATA.DBF |
1G |
PLAN_INDX01.DBF |
3.5G |
PLAN_DATA01.DBF |
1.7G |
B实例:
A_INDX.DBF |
1G |
A_INDX02.DBF |
5G |
A_DATA.DBF |
16.8G |
A_DATA02.DBF |
28G |
SYSTEM01.DBF |
563M |
SYSAUX01.DBF |
550M |
UNDOTBS01.DBF |
5G |
TEMP01.DBF |
2.6G |
一.首先,是考虑缩减数据库空间
- 查找大表
Sql语句:
select t.owner,t.segment_name,segment_type,sum(bytes)/1024/1024/1024 o_size from dba_segments t
where segment_type = 'TABLE'
group by t.owner,t.segment_name,segment_type
having sum(bytes)/1024/1024/1024 > 1
查找分区表的条件是where segment_type = 'TABLE PARTITION'
结果:
A |
DATA_REPORT_LOG |
1.1298828125 |
A |
TASKPROCESS_INFO |
1.494140625 |
A |
FAULT_DATA |
1.099609375 |
A |
EXCEED_DATA |
2.099609375 |
ITEM_HIS |
10.099609375 |
- 实际查询EXCEED_DATA表中的记录为0,但是它占用的空间依然是2G,这是因为删除记录使用的是delete语句,delete语句是不释放表空间的,所以这里要使用truncate截短EXCEED_DATA记录,然后再强制释放表空间。
Sql:
TRUNCATE TABLE EXCEED_DATA
alter table EXCEED_DATA enable row movement
alter table EXCEED_DATA shrink space
然后查询表空间使用情况
Sql语句:
SELECT a.tablespace_name "表空间名",
total "表空间大小",
free "表空间剩余大小",
(total - free) "表空间使用大小",
total / (1024 * 1024 * 1024) "表空间大小(G)",
free / (1024 * 1024 * 1024) "表空间剩余大小(G)",
(total - free) / (1024 * 1024 * 1024) "表空间使用大小(G)",
round((total - free) / total, 4) * 100 "使用率 %"
FROM (SELECT tablespace_name, SUM(bytes) free
FROM dba_free_space
GROUP BY tablespace_name) a,
(SELECT tablespace_name, SUM(bytes) total
FROM dba_data_files
GROUP BY tablespace_name) b
WHERE a.tablespace_name = b.tablespace_name
结果:
表空间名 |
表空间大小(G) |
表空间剩余大小(G) |
表空间使用大小(G) |
使用率 % |
A_INDX |
5.9765625 |
2.432617188 |
3.543945313 |
59.3 |
QUEST_DATA |
0.09765625 |
0.094726563 |
0.002929688 |
3 |
SYSAUX |
0.52734375 |
0.021850586 |
0.505493164 |
95.86 |
USERS |
0.063476563 |
0.001586914 |
0.061889648 |
97.5 |
SYSTEM |
0.537109375 |
0.006774902 |
0.530334473 |
98.74 |
UNDOTBS3 |
0.09765625 |
0.095581055 |
0.002075195 |
2.13 |
A_DATA |
42.7890625 |
16.84375 |
25.9453125 |
60.64 |
- 然后考虑缩减A_DATA这个数据库文件,这里涉及一个HWM(高水位)的概念,需要查询表空间的最大block的位置
参考如下资料:
测试的时候向数据库中插入了大量的数据,测试完成后删除了测试用户以及其全部数据,但是数据文件却没有缩小。经查阅资料之后发现这是 Oracle “高水位”所致,那么怎么把这些数据文件的大小降下来呢?解决办法如下: 概念: 表空间的相关知识请见这里,详细的介绍了 Oracle 数据库的存储结构。 高水位:High Water Mark (HWM),是段(Segment)的一个指标,界定了段(Segment)曾经配置过的 block 水位。 据说,随着数据的 insert,所使用段(Segment)的数据块(data block)也不断增加,这时候高水位(HWM)也随着上升。当数据被删除后(无论是 delete 还是 truncate table)虽然被占用的数据块(data block)已经相应减少,但是高水位(HWM)并不会随之下降。当高水位(HWM)下存在大量的空白数据块(data block)时,如果发生全表扫描(Full Table Scan, FTS)就会造成很多额外的 IO。因为全表扫描(FTS)的时候读取段(Segment)中的数据块(data block)会一直读取到高水位(HWM)才结束。高水位(HWM)就是段(Segment)中数据块(data block)有没有使用的分界线,所以全表扫描(FTS)所花费的时间不但不会因为数据的删除而减少,反而会增加。(关于此段查询效率的内容有待验证,笔者未亲自验证。不过可以确定的是高水位确实不会随着数据的删除而下降。) 降低高水位的正确做法是先降低HWM,再确定实际占有大小,再resize数据文件。 数据文件比较多,我们用其中一个较大的文件做为 Demo,其它数据文件如法炮制即可。我选择的文件是:D:\oracle\product\10.2.0\oradata\orcl\USERS01.DBF 1.4GB 左右。 1.登录 sqlplus: 语法:sqlplus username/password@hostname:port/sid 例:sqlplus system/orcl@localhost:1521/orcl
2.查询这个数据文件的编号: SQL> select file#, name from v$datafile; FILE# NAME 1 D:\ORACLE\PRODUCT\10.2.0\ORADATA\ORCL\SYSTEM01.DBF 2 D:\ORACLE\PRODUCT\10.2.0\ORADATA\ORCL\UNDOTBS01.DBF 3 D:\ORACLE\PRODUCT\10.2.0\ORADATA\ORCL\SYSAUX01.DBF 4 D:\ORACLE\PRODUCT\10.2.0\ORADATA\ORCL\USERS01.DBF 可以看到,我们要操作的数据文件的编号是4。 2.根据文件 ID 查询这个数据文件最大数据块(data block)的编号:(似乎这个最大编号可以代表该数据文件中数据块的数量,这一点有待考证。) SQL> select max(block_id) from dba_extents where file_id=4; MAX(BLOCK_ID) 3.计算该表空间实际占用的空间: --查询数据块的大小,单位是 byte SQL> show parameter db_block_size; NAME TYPE VALUE --8192 byte = 8 kb --接下来计算该表空间占用的物理空间 SQL> select 65673 * 8 / 1024 from dual; 65673*8/1024 --实际占用的物理空间是 513MB 多点 4.最后一步,把我们的数据文件尺寸修改得比这个表空间实际占用的物理空间大点就行了: SQL> alter database datafile 'D:\oracle\product\10.2.0\oradata\orcl\USERS01.DBF' resize 600m; 数据库已更改。 OK,数据文件从修改前的 1.4GB 变成了 600MB。对于其它的数据文件,大家也知道如何收缩了吧? |
按照资料上操作,发现最大的数据块的编号和数据库文件A_DATA.DBF几乎相同。原因可能是虽然我释放了10G的表空间,但是因为数据段不连续,最高水位的block编号依然没有减小。
二.缩减回滚段表空间
在操作上述步骤过程中,发现回滚段表空间几乎没有使用,而开发环境中目前也没有未提交的事务,但是回滚段表空间两个实例却分别占用了14G和5G的磁盘空间,所以考虑采用释放回滚段表空间的方法。
- 首先查看回滚段状态
Sql语句:
select *
From
dba_rollback_segs r, v$rollstat v
Where
r.segment_id = v.usn(+)
order
by segment_name;
结果:
SYSTEM SYS SYSTEM ONLINE
_SYSSMU12$ PUBLIC UNDOTBS3 ONLINE
_SYSSMU13$ PUBLIC UNDOTBS3 ONLINE
_SYSSMU14$ PUBLIC UNDOTBS3 ONLINE
_SYSSMU15$ PUBLIC UNDOTBS3 ONLINE
_SYSSMU16$ PUBLIC UNDOTBS3 ONLINE
_SYSSMU17$ PUBLIC UNDOTBS3 ONLINE
_SYSSMU18$ PUBLIC UNDOTBS3 ONLINE
_SYSSMU19$ PUBLIC UNDOTBS3 ONLINE
_SYSSMU20$ PUBLIC UNDOTBS3 ONLINE
_SYSSMU21$ PUBLIC UNDOTBS3 ONLINE
所有的回滚段都是online
- 新建回滚段文件,并将数据库的回滚段指向该文件
create undo tablespace undotbs2 datafile ORALCE安装目录 + '\ORADATA\GGG\UNDOTBS02.DBF' size 100M; |
alter system set undo_tablespace = undotbs2 scope = both; |
- 等待原回滚段offline
- 删除原回滚段表空间
drop tablespace undotbs1 including contents;
drop tablespace UNDOTBS1 INCLUDING CONTENTS and datafiles;
但是回滚段文件在磁盘上依然不会删除
- 手动删除回滚段文件
停止实例服务,手动删除
在第一次的操作过程中,在查找到超过10G的大表后,我直接drop该表,但是实际上drop操作并没有真正释放表空间,而是将表移动到回收站中,后来我又闪回该表之后,再截短
闪回sql:
flashback table ITEM_HIS to before drop