Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2583097
  • 博文数量: 323
  • 博客积分: 10211
  • 博客等级: 上将
  • 技术积分: 4934
  • 用 户 组: 普通用户
  • 注册时间: 2006-08-27 14:56
文章分类

全部博文(323)

文章存档

2012年(5)

2011年(3)

2010年(6)

2009年(140)

2008年(169)

分类: Oracle

2008-06-18 16:41:21

  从8i开始,oracle开始提供Move的命令。我们通常使用这个命令,将一个table segment从一个tablespace移动到另一个tablespace。Move实际上是在block之间物理的copy数据,那么,我们可以通过这种方式来降低table的HWM。我们先通过一个实验来看看move是如何移动数据的。
 
1.建表并插入数据:
SQL> create table sjh.test1(id int) tablespace users;
表已创建。
SQL> insert into sjh.test1 values(1);
已创建 1 行。
SQL> insert into sjh.test1 values(2);
已创建 1 行。
SQL> insert into sjh.test1 values(3);
已创建 1 行。
SQL> insert into sjh.test1 values(4);
已创建 1 行。
SQL> insert into sjh.test1 values(5);
已创建 1 行。
SQL> insert into sjh.test1 values(6);
已创建 1 行。
SQL> insert into sjh.test1 values(7);
已创建 1 行。
SQL> insert into sjh.test1 values(8);
已创建 1 行。
SQL> commit;
提交完成。
SQL> select * from sjh.test1;
        ID
----------
         1
         2
         3
         4
         5
         6
         7
         8
已选择8行。
 
2.查看表的rowid信息和block id信息:
SQL> select rowid,id from sjh.test1;
ROWID                      ID
------------------ ----------
AAAMlQAAEAAAABHAAA          1
AAAMlQAAEAAAABHAAB          2
AAAMlQAAEAAAABHAAC          3
AAAMlQAAEAAAABHAAD          4
AAAMlQAAEAAAABHAAE          5
AAAMlQAAEAAAABHAAF          6
AAAMlQAAEAAAABHAAG          7
AAAMlQAAEAAAABHAAH          8
已选择8行。
SQL> select EXTENT_ID,FILE_ID,RELATIVE_FNO,BLOCK_ID,BLOCKS
  2  from dba_extents  where segment_name='TEST1';
 EXTENT_ID    FILE_ID RELATIVE_FNO   BLOCK_ID     BLOCKS
---------- ---------- ------------ ---------- ----------
         0          4            4         65          8
 
--8条记录都在一个块上(AAAABH
这里简单介绍一下ROWID的知识:
ROWID 在磁盘上需要10 个字节的存储空间并使用18 个字符来显示它包含下列组件:
数据对象编号:每个数据对象如表或索引在创建时都分配有此编号,并且此编号在数据库中是唯一的;
相关文件编号:此编号对于一个表空间中的每个文件是唯一的;
块编号:表示包含此行的块在文件中的位置;
行编号:标识块头中行目录位置的位置;
在内部数据对象编号需要32 位,相关文件编号需要10 位,块编号需要22,位行编号需要16 位,加起来总共是80 位或10 个字节,ROWID 使用以64 为基数的编码方案来显示该方案将六个位置用于数据对象,编号三个位置用于相关文件编号六个位置用于块编号三个位置用于行编号以64 为基数的编码方案使用字符A-Z a-z 0-9 + 和/共64 个字符,如下例所示:
AAAMlQ AAE AAAABH AAA
在本例中
AAAMlQ   是数据对象编号
AAE      是相关文件编号
AAAABH   是块编号
AAA      是行编号

3.做一些DML操作,再观察ROWID有没有发生变化:
SQL> delete from sjh.test1 where id=1;
已删除 1 行。
SQL> delete from sjh.test1 where id=3;
已删除 1 行。
SQL> delete from sjh.test1 where id=5;
已删除 1 行。
SQL> commit;
提交完成。
SQL>  select rowid,id from sjh.test1;
ROWID                      ID
------------------ ----------
AAAMlQAAEAAAABHAAB          2
AAAMlQAAEAAAABHAAD          4
AAAMlQAAEAAAABHAAF          6
AAAMlQAAEAAAABHAAG          7
AAAMlQAAEAAAABHAAH          8
 
--我们看到ROWID保持不变。
 
4.做MOVE操作,然后观察ROWID的情况:
SQL> alter table sjh.test1 move;
表已更改。
SQL> select rowid,id from sjh.test1;
ROWID                      ID
------------------ ----------
AAAMlRAAEAAAABMAAA          2
AAAMlRAAEAAAABMAAB          4
AAAMlRAAEAAAABMAAC          6
AAAMlRAAEAAAABMAAD          7
AAAMlRAAEAAAABMAAE          8
SQL>  select EXTENT_ID,FILE_ID,RELATIVE_FNO,BLOCK_ID,BLOCKS
  2   from dba_extents  where segment_name='TEST1';
 EXTENT_ID    FILE_ID RELATIVE_FNO   BLOCK_ID     BLOCKS
---------- ---------- ------------ ---------- ----------
         0          4            4         73          8
--ROWID发生变化BLOCK_ID由原来的65变为73,BLOCK的编号由原来的AAAABH变为AAAABM
 
5.move对HWM的影响:
这里引用网友yjz0065的一个例子:

SQL> create table my_objects tablespace HWM

2        as select * from all_objects;

SQL> delete from my_objects where rownum<10000;

9999 rows deleted

SQL> select count(*) from my_objects;

  COUNT(*)

----------

     21015

SQL> exec show_space(p_segname => 'MY_OBJECTS',p_owner => 'DLINGER',p_type => 'TABLE');

Total Blocks............................425

Total Bytes.............................3481600

Unused Blocks...........................3

Unused Bytes............................24576

Last Used Ext FileId....................11

Last Used Ext BlockId...................1294

Last Used Block.........................2

 

这里HWM=425 - 3 + 1 = 423

然后对table MY_OBJECTS进行move操作:

SQL> alter table MY_OBJECTS move;

表已更改。

SQL> exec show_space(p_segname => 'MY_OBJECTS',p_owner => 'DLINGER',p_type => 'TABLE');

Total Blocks............................290

Total Bytes.............................2375680

Unused Blocks...........................1

Unused Bytes............................8192

Last Used Ext FileId....................11

Last Used Ext BlockId...................1584

Last Used Block.........................4

 

我们可以看到,table MY_OBJECTSHWM423移动到290tableHWM降低了!(show_space是自定义的一个过程)。

 

 

Move的一些用法:

以下是alter table move子句的完整语法,我们介绍其中的几点:

MOVE [ONLINE]   [segment_attributes_clause]   [data_segment_compression]  [index_org_table_clause]  [ { LOB_storage_clause | varray_col_properties }    [ { LOB_storage_clause | varray_col_properties } ]...  ]  [parallel_clause]

 

a. 我们可以使用move将一个table从当前的tablespace上移动到另一个tablespace上,如:

alter table t move tablespace tablespace_name;

b. 我们还可以用move来改变table已有的block的存储参数,如:

alter table t move storage (initial 30k  next 50k);  

c.另外,move操作也可以用来解决table中的行迁移的问题。

 

使用move的一些注意事项: 

a.  table上的index需要rebuild

在前面我们讨论过,move操作后,数据的rowid发生了改变,我们知道,index是通过rowidfetch数据行的,所以,table上的index是必须要rebuild的。

SQL>  create index i_my_objects on my_objects (object_id);

Index created

 

SQL> alter table my_objects move;

Table altered

 

SQL> select index_name,status from user_indexes where index_name='I_MY_OBJECTS';

 

INDEX_NAME                     STATUS

------------------------------ --------

I_MY_OBJECTS                   UNUSABLE

 

从这里可以看到,当table MY_OBJECTS进行move操作后,该table 上的inedx的状态为UNUSABLE,这时,我们可以使用alter index I_MY_OBJECTS rebuild online的命令,对index I_MY_OBJECTS进行在线rebuild

 

b.      move时对table的锁定

当我们对table MY_OBJECTS进行move操作时,查询v$locked_objects视图可以发现,table MY_OBJECTS上加了exclusive lock

SQL>select OBJECT_ID, SESSION_ID,ORACLE_USERNAME,LOCKED_MODE from v$locked_objects;

 

 OBJECT_ID SESSION_ID ORACLE_USERNAME    LOCKED_MODE

---------- ---------- ------------------ -----------

     32471          9 DLINGER                      6

SQL> select object_id from user_objects where object_name = 'MY_OBJECTS';

 

 OBJECT_ID

----------

     32471

这就意味着,table在进行move操作时,我们只能对它进行select的操作。反过来说,当我们的一个sessiontable进行DML操作且没有commit时,在另一个session中是不能对这个table进行move操作的,否则oracle会返回这样的错误信息:ORA-00054: 资源正忙,要求指定 NOWAIT

 

c.      关于move时空间使用的问题:

当我们使用alter table move来降低tableHWM时,有一点是需要注意的,这时,当前的tablespace中需要有1倍于table的空闲空间以供使用:

SQL> CREATE TABLESPACE TEST1

  2  DATAFILE 'D:\ORACLE\ORADATA\ORACLE9I\TEST1.dbf' SIZE 5M

  3  UNIFORM SIZE 128K ;


SQL> create table my_objects  tablespace test1 as select * from all_objects;

表已创建。


SQL> select bytes/1024/1024 from user_segments where segment_name='MY_OBJECTS';


BYTES/1024/1024

---------------

          3.125

 

SQL> alter table MY_OBJECTS move;


alter table MY_OBJECTS move

            *

ERROR 位于第 1 :

ORA-01652: 无法通过16(在表空间TEST1中)扩展 temp


SQL> ALTER DATABASE

  2  DATAFILE 'D:\ORACLE\ORADATA\ORACLE9I\TEST1.DBF' RESIZE  7M;


数据库已更改。

SQL> alter table MY_OBJECTS move;

表已更改。

 
 
阅读(2847) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~