关于 move 和 shrink 的一些总结

来源:互联网 发布:淘宝助理下载安装 编辑:程序博客网 时间:2024/06/05 04:43

测试结论:

一、move
1. move过程中需要额外的表空间,需要的大小大约等于当前表中数据量的大小,move结束后立即释放该额外空间。
2. move过程中对表加排它锁,会影响其他session的DML操作。
3. move操作并不会维护索引,因此move完毕后需要对索引rebuild。
4. move操作会降低HWM,但是并不会释放HWM以上的空块,也就是说,move只会对HWM以下的块进行操作。
5. move操作的一些相关测试数据:以2000000数据(233M)为例,删除800000条数据,执行move操作。
大概用时4秒,共产生了319K的redo,56K的undo。表由233M缩小至145M。
6. move操作可以完全消除行迁移。
7. move操作后,为表分配的数据段位置发生了改变,即段头块的位置发生了改变。

二、shrink

  1. shrink过程中并没有用到额外的表空间。
  2. shrink操作其实可以分为两步:
    第一步:对数据进行重组,即只会整理碎片,不会降低高水位,也就是说不会释放空间。
    通过一系列的delete/insert组合来完成,具体的语法是 alter table t1 shrink space compact。该过程会在表上加共享锁,在移动的行中加排它锁。并且会维护索引。
    第二步:降低HWM,回收空间,与move不同的是,shrink可以回收HWM以上的块。该过程会在表上加排它锁,因此业务繁忙时并不适合执行该降低HWM的操作。
  3. shrink操作会维护索引,但是不会对索引进行碎片整理。如果加入cascade选项,那么维护索引的同时会对索引进行碎片整理。
  4. shrink操作的一些相关测试数据:以2000000数据(233M)为例,删除800000条数据,分两步执行shrink操作。
    数据重组大概用时1分钟58秒,共产生了895M的redo,353M的undo。回收HWM阶段仅用1秒,产生了4K的redo,1K的undo。表由233M缩小至226M。
  5. shrink操作不能完全消除行迁移。
  6. shrink操作后,为表分配的数据段位置并没有发生变化,即段头块的位置没有改变。

(1) oracle 的move 操作,rowid 如何变化?
创建一张测试表,插入十条数据
create table t (id int,name varchar2(20));
insert into t values(1,’a1’);
insert into t values(2,’a2’);
insert into t values(3,’a3’);
insert into t values(4,’a4’);
insert into t values(5,’a5’);
insert into t values(6,’a6’);
insert into t values(7,’a7’);
insert into t values(8,’a8’);
insert into t values(9,’a9’);
insert into t values(10,’a10’);
commit;

查看这个表的rowid,看一下这个表的块号
select rowid from t;

ROWID

AAATaSAAEAAAAIOAAA
AAATaSAAEAAAAIOAAB
AAATaSAAEAAAAIOAAC
AAATaSAAEAAAAIOAAD
AAATaSAAEAAAAIOAAE
AAATaSAAEAAAAIOAAF
AAATaSAAEAAAAIOAAG
AAATaSAAEAAAAIOAAH
AAATaSAAEAAAAIOAAI
AAATaSAAEAAAAIOAAJ
10 rows selected

看一下这个表的块号
SQL> select dbms_rowid.rowid_block_number(rowid) from t;

DBMS_ROWID.ROWID_BLOCK_NUMBER(

                       526                       526                       526                       526                       526                       526                       526                       526                       526                       526

10 rows selected

delete from t where mod(id,2)=1;

SQL> select dbms_rowid.rowid_block_number(rowid) from t;

DBMS_ROWID.ROWID_BLOCK_NUMBER(

                       526                       526                       526                       526                       526

SQL> alter table t move;
Table altered

SQL> select rowid from t;

ROWID

AAATaTAAEAAAetbAAA
AAATaTAAEAAAetbAAB
AAATaTAAEAAAetbAAC
AAATaTAAEAAAetbAAD
AAATaTAAEAAAetbAAE

SQL> select dbms_rowid.rowid_block_number(rowid) from t;

DBMS_ROWID.ROWID_BLOCK_NUMBER(

                    125787                    125787                    125787                    125787                    125787

可以看出move操作后,数据的rowid发生了改变,index是通过rowid来fetch数据行的,
所以,table上的index是必须要rebuild的
(2) move 操作索引会失效

create index idx_id on t(id);
alter table t move;
select index_name,status from user_indexes where index_name=’IDX_ID’;
INDEX_NAME STATUS


IDX_ID UNUSABLE
t表上的inedx的状态为UNUSABLE,这时,我们可以使用alter index idx_id rebuild online;的命令,
进行在线rebuild。
SQL> alter index idx_id rebuild online;
Index altered

SQL> select index_name,status from user_indexes where index_name=’IDX_ID’;
INDEX_NAME STATUS


IDX_ID VALID

3) move 操作的锁问题
另外当我们对表进行move 的时候,需要加锁,我们可以看下
建立一个大表
建表脚本:

create or replace procedure create_table(p_tabname varchar2,
p_tabcnt number default 100000,
p_tbs varchar2 default ‘users’)
authid current_user
as
v_create_table varchar2(100);
l_cnt number := 0;
v_sql varchar2(500);
e_error exception;
e_tbs_not_exists exception;
l_tabsize number;
e_pri exception;
pragma exception_init(e_error, -00955);
pragma exception_init(e_tbs_not_exists, -00959);
pragma exception_init(e_pri,-00942);
begin
begin
v_create_table := ‘create table ’ || p_tabname ||
’ nologging tablespace ’ || p_tbs ||
’ as select * from dba_objects where 1 = 2’;
execute immediate v_create_table;
exception
when e_error then
execute immediate ‘drop table ’ || p_tabname || ’ purge’;
dbms_output.put_line(‘已经存在表:’ || p_tabname || ’ ,但已删除。’);
execute immediate v_create_table;
end;
while l_cnt < p_tabcnt
loop
v_sql := ‘insert /+ append / into ’ || p_tabname ||
’ select OWNER, OBJECT_NAME, SUBOBJECT_NAME,rownum + ’ ||
l_cnt || ‘,DATA_OBJECT_ID,OBJECT_TYPE, CREATED, LAST_DDL_TIME,TIMESTAMP,
STATUS, TEMPORARY, GENERATED, SECONDARY,NAMESPACE,EDITION_NAME
from dba_objects where rownum <= ’ ||
to_char(p_tabcnt - l_cnt);
execute immediate v_sql;
l_cnt := l_cnt + sql%rowcount;
commit;
end loop;
dbms_output.put_line(‘已创建完表: ’ || p_tabname || ’ 。记录数:’ || p_tabcnt);
/*select bytes / 1024 / 1024
into l_tabsize
from user_segments
where owner = sys_context(‘userenv’, ‘current_user’)
and segment_name = upper(p_tabname);*/
select bytes / 1024 / 1024
into l_tabsize
from user_segments
where segment_name = upper(p_tabname);
dbms_output.put_line(‘表的segment_size: ’ || l_tabsize || ’ M’);
exception
when e_pri then
dbms_output.put_line(‘没权限访问 dba_objects。’);
when e_tbs_not_exists then
dbms_output.put_line(‘表空间: ’ || p_tbs || ’ 不存在。’);
end;
建一个大表:
SQL> exec create_table(‘T1’,2000000);
PL/SQL procedure successfully completed

SQL> alter table t1 move;

打开另外一个会话,可以看到:

SELECT b.session_id AS sid,
NVL(b.oracle_username, ‘(oracle)’) AS username,
a.owner AS object_owner,
a.object_name,
Decode(b.locked_mode, 0, ‘None’,
1, ‘Null (NULL)’,
2, ‘Row-S (SS)’,
3, ‘Row-X (SX)’,
4, ‘Share (S)’,
5, ‘S/Row-X (SSX)’,
6, ‘Exclusive (X)’,
b.locked_mode) locked_mode,
b.os_user_name
FROM dba_objects a,
v$locked_object b
WHERE a.object_id = b.object_id;

   SID USERNAME                       OBJECT_OWNER                   OBJECT_NAME                                                                      LOCKED_MODE                              OS_USER_NAME

   130 SCOTT                          SCOTT                          T1                                                                               Exclusive (X)                            PC-20160628ZXVS\Administrator

总结:6号锁,独占锁.,DML是加共享锁,6号锁与其他锁不兼容
这就意味着,table在进行move操作时,我们只能对它进行select的操作,DML会全部阻塞(move生成的undo和redo是非常少的)。反过来说,当我们的一个session对table进行DML操作且没有commit时,
在另一个session中是不能对这个table进行move操作的,否则oracle会返回这样的错误信息:ORA-00054(资源正忙)

(4) 现在来看下move 能否降低高水位?

0 0
原创粉丝点击