Oracle 碎片问题
1>碎片对系统的影响
当要满足一个空间要求时,数据库将首先查找当前最大的自由范围,而"最大"自由范围逐渐变小,要找到一个足够大的自由范围已变得越来越困难,从而导致表空间中的速度障碍,使数据库的空间分配愈发远离理想状态
部分的extent无法得以自动合并,浪费了大量的表空间
2>自由范围的碎片计算
FSFI(free space fragmentation index 自由空间碎片索引)
FSFI=100*sqrt(max(extent)/sum(extents))*1/sqrt(sqrt(count(extents)))
FSFI最大100(理想的单文件表空间)
-- --查看所有表空间的碎片程度(值在30以下表示碎片很多)
|
--运行后
TABLESPACE_NAME SUM(BYTES) SUM(FREE) SUM(FREE)*100/SUM(BYTES)
------------------------------ ---------- ---------- ------------------------
SYSTEM 503316480 9568256 1.90104167
SYSAUX 251658240 9240576 3.671875
UNDOTBS1 152043520 129368064 85.0862069
USERS 5242880 4784128 91.25
补充
--查找数据库某个表空间内最大连续的自由空间大小
SELECT tablespace_name,max(bytes)/1024/1024 "max_free_space(M)"
FROM dba_free_space
GROUP BY tablespace_name
ORDER BY 1;
3>碎片整理
--盘区(extent)的碎片整理:alter tablespace temp coalesce
SELECT 'alter tablespace ' || TABLESPACE_NAME || ' coalesce ;'
FROM DBA_FREE_SPACE_COALESCED
WHERE PERCENT_EXTENTS_COALESCED < 100 OR PERCENT_BLOCKS_COALESCED < 100;
--段(segment)碎片整理,查看数据字典dba_segments,segment 的信息可以查看dba_extents
--表段,索引段等。每种段都可以碎片的整理
3.1>表段碎片整理
方式一:import/export
最简单的方法是用正确的存储参数将这个段重建,将旧表中的数据插入到新表,同时删除旧表。Import/export来完成。
Export命令有个(压缩标志)这个标志在读表时会引发export确定该表所分配的物理空间量,它会向输出转储文件写入一个新的初始化存储参数--等于全部所分配空间。若这个表关闭, 则使用import命令重新生成。
$exp user/password file=exp.dmp compress=y grants=y indexes=y tables(table1,table2);
$imp user/password file=exp.emp commit=y buffer=64000 tables=(table1,table2);
除了exp/imp,还可以使用shrink table 或alter table tbname move
方式二:Shrink table
http://blog.csdn.net/leishifei/archive/2011/04/23/6347524.aspx
介绍:10g开始,提供shrink命令
表空间支持自动段空间管理,使用这个特性,降低HWM
分为两个阶段
1.数据重装(compact):一系列insert,delete操作,将数据尽量排列在段的前面,这个过程需要在表上加RX锁,即,只在需要移动的行上加锁。涉及到rowid的改变,需要enable row movement同时disable基于rowid的trigger,对业务影响较小
语法:
$shrink space compact
SQL>alter table <table_name> enable row movement --会造成引用表的XX对象(存储,包,视图)变为失效,执行utlrp.sql来编译无效的对象
2.HWM的调整:调整HWM位置,释放空间数据块,需要在表上加X锁,会造成表上所有DML语句阻塞,业务繁忙期影响较大。
语法:
alter table <table_name> shrink space [ <null> | compact | cascade ];
alter table <table_name> shrink space compcat;
收缩表,相当于把块中数据打结实了,但会保持 high water mark;
alter table <tablespace_name> shrink space;
收缩表,降低 high water mark;
alter table <tablespace_name> shrink space cascade;
收缩表,降低 high water mark,并且相关索引也要收缩一下下。
alter index idxname shrink space;
回缩索引
补充
alter table move
移动high water mark,但是并不会释放空间。shrink space移动高水位线,并且释放空间。
测试
普通表
Sql脚本,改脚本会生成相应的语句
select'alter table '||table_name||' enable row movement;'||chr(10)||'alter table '||table_name||' shrink space;'||chr(10)from user_tables;
select'alter index '||index_name||' shrink space;'||chr(10)from user_indexes;
分区表的处理
进行shrink space时,发生ORA-10631,shrink space有限制
在表上建有索引(包括全文索引)会失败
Sql
select 'alter table '||table_name||' enable row movement;'||chr(10)||'alter table '||table_name||' shrink space;'||chr(10) from user_tables where ;
select 'alter index '||index_name||' shrink space;'||chr(10) from user_indexes where uniqueness='NONUNIQUE' ;
select 'alter table '||segment_name||' modify subpartition '||partition_name||' shrink space;'||chr(10) from user_segments where segment_type='TABLE SUBPARTITION' ';
Shrink的几个问题
1 shrink后index是否需要rebuild
|
2.shrink时对table的lock 对table进行shrink,对table的锁定,v$locked_objects,被加上了row-x(SX)的lock
3.2>索引段碎片整理
--把索引重建(碎片整理后,很多索引会变成unusable状态,必须让塔变成void状态)
FOR REC IN (SELECT INDEX_NAME FROM USER_INDEXES ) --WHERE STATUS='UNUSABLE'
LOOP
tmp_val:='ALTER INDEX '||REC.INDEX_NAME ||' REBUILD';
BEGIN
EXECUTE IMMEDIATE tmp_val;
DBMS_OUTPUT.put_line (tmp_val);
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line ('Error: ' || tmp_val || '!');
END;
END LOOP;
END;