关于 move 和 shrink 的一些总结

原创 2017年01月02日 22:23:10

测试结论:

一、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 能否降低高水位?

版权声明:本文为博主原创文章,未经博主允许不得转载。

表碎片整理时shrink和move如何选择(转)——写的很好

原文地址:http://blog.itpub.net/29821678/viewspace-1270131/ 整理表碎片通常的方法是move表,当然move是不能在线进行的,而且move后相应的...
  • lijingkuan
  • lijingkuan
  • 2016年04月25日 23:15
  • 1570

alter table move跟shrink space的区别

author:skatetime2010-05-28alter table move跟shrink space的区别今天主要从两点说他们的区别: 1. 碎片的整理2.空间的收缩 SQL> select...
  • wyzxg
  • wyzxg
  • 2010年05月28日 20:44
  • 20259

关于 move 和 shrink 的一些总结

测试结论:一、move 1. move过程中需要额外的表空间,需要的大小大约等于当前表中数据量的大小,move结束后立即释放该额外空间。 2. move过程中对表加排它锁,会影响其他session...
  • Angelina7
  • Angelina7
  • 2017年01月02日 22:23
  • 703

alter table move 与shrink space的区别

案例: 同事将一关键表中删了多余的300w条数据后,程序就变的异常缓慢。分析得出,应该是表空间碎片过多,旧的索引效率过低。 执行下面两句话: alter table ycsbt_qyyg...
  • zhjxixi
  • zhjxixi
  • 2012年06月13日 23:15
  • 7390

alter table move和alter table shrink space的区别

Alter table move和alter table shrinkspace的区别 1)使用alter tablemove,会把表格最多收缩到创建表格时的storage子句指定的初始大小,使用a...
  • gumengkai
  • gumengkai
  • 2016年04月05日 16:38
  • 664

JavaScript关于创建对象和继承的一些总结

本文总结了JavaScript创建对象和实现继承的多种方式。 原文地址:https://www.zzfweb.cn/post/2017-12-26-create-obj.html 创建对象 ...
  • wdx__123
  • wdx__123
  • 2017年12月27日 10:59
  • 66

实验: Oracle中表shrink与move后index的状态

1 move时实验 SQL> create table my_objects_move tablespace ASSM as select * from all_objects where rown...
  • huang_xw
  • huang_xw
  • 2011年11月27日 12:16
  • 2684

一些时间类型的总结

1. 系统时间函数         在编程时,时间函数不可避免的会被使用。linux系统下相关时间的数据结构有time_t,timeval,timespec,tm,clock_t; windows下...
  • pud_zha
  • pud_zha
  • 2013年10月01日 01:52
  • 829

对时间的一些操作总结

由于项目要对时间进行一些数学运算,要使用 access 数据库交互一些时间的信息,于是乎便有了下文。。。 CTime Comparison OperatorsBOOL operator ==( CTi...
  • xum2008
  • xum2008
  • 2010年09月08日 17:15
  • 464

关于博弈论基础知识的一些总结

文章PDF文档:链接地址 博弈论是二人或多人在平等的对局中各自利用对方的策略变换自己的对抗策略,达到取胜目标的理论。 基础的基础 a) 当前执行者想赢。这个是必要的,有时候题目中判别...
  • xf_zhen
  • xf_zhen
  • 2016年07月23日 18:51
  • 485
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:关于 move 和 shrink 的一些总结
举报原因:
原因补充:

(最多只允许输入30个字)