Oracle中的move命令
?
??? 從8i開始,oracle開始提供Move的命令。我們通常使用這個(gè)命令,將一個(gè)table segment從一個(gè)tablespace移動(dòng)到另一個(gè)tablespace。Move實(shí)際上是在block之間物理的copy數(shù)據(jù),那么,我們可以通過(guò)這種方式來(lái)降低table的HWM。我們先通過(guò)一個(gè)實(shí)驗(yàn)來(lái)看看move是如何移動(dòng)數(shù)據(jù)的。
?
?
1.建表并插入數(shù)據(jù):
?
SQL> create table sjh.test1(id int) tablespace users;
?
表已創(chuàng)建。
?
SQL> insert into sjh.test1 values(1);
?
已創(chuàng)建 1 行。
?
SQL> insert into sjh.test1 values(2);
?
已創(chuàng)建 1 行。
?
SQL> insert into sjh.test1 values(3);
?
已創(chuàng)建 1 行。
?
SQL> insert into sjh.test1 values(4);
?
已創(chuàng)建 1 行。
?
SQL> insert into sjh.test1 values(5);
?
已創(chuàng)建 1 行。
?
SQL> insert into sjh.test1 values(6);
?
已創(chuàng)建 1 行。
?
SQL> insert into sjh.test1 values(7);
?
已創(chuàng)建 1 行。
?
SQL> insert into sjh.test1 values(8);
?
已創(chuàng)建 1 行。
?
S
QL> 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條記錄都在一個(gè)塊上(AAAABH)
?
這里簡(jiǎn)單介紹一下ROWID的知識(shí):ROWID 在磁盤上需要10個(gè)字節(jié)的存儲(chǔ)空間并使用18個(gè)字符來(lái)顯示它包含下列組件:
?
數(shù)據(jù)對(duì)象編號(hào):每個(gè)數(shù)據(jù)對(duì)象如表或索引在創(chuàng)建時(shí)都分配有此編號(hào),并且此編號(hào)在數(shù)據(jù)庫(kù)中是唯一的;
相關(guān)文件編號(hào):此編號(hào)對(duì)于一個(gè)表空間中的每個(gè)文件是唯一的;
塊編號(hào):表示包含此行的塊在文件中的位置;
行編號(hào):標(biāo)識(shí)塊頭中行目錄位置的位置;
?
在內(nèi)部數(shù)據(jù)對(duì)象編號(hào)需要32 位,相關(guān)文件編號(hào)需要10 位,塊編號(hào)需要22,位行編號(hào)需要16 位,加起來(lái)總共是80 位或10 個(gè)字節(jié),ROWID 使用以64 為基數(shù)的編碼方案來(lái)顯示該方案將六個(gè)位置用于數(shù)據(jù)對(duì)象,編號(hào)三個(gè)位置用于相關(guān)文件編號(hào)六個(gè)位置用于塊編號(hào)三個(gè)位置用于行編號(hào)以64 為基數(shù)的編碼方案使用字符A-Z a-z 0-9 + 和/共64 個(gè)字符,
?
如下例所示:AAAMlQ AAE AAAABH AAA
?
在本例中
AAAMlQ ?? 是數(shù)據(jù)對(duì)象編號(hào)
AAE?????? 是相關(guān)文件編號(hào)
AAAABH?? 是塊編號(hào)
AAA????? 是行編號(hào)
?
?
3.做一些DML操作,再觀察ROWID有沒(méi)有發(fā)生變化:
?
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發(fā)生變化BLOCK_ID由原來(lái)的65變?yōu)?3,BLOCK的編號(hào)由原來(lái)的AAAABH變?yōu)锳AAABM
?
?
5.move對(duì)HWM的影響:
?
這里引用網(wǎng)友yjz0065的一個(gè)例子:
?
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
然后對(duì)table MY_OBJECTS進(jìn)行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_OBJECTS的HWM從423移動(dòng)到290,table的HWM降低了!(show_space是自定義的一個(gè)過(guò)程)。
?
?
?
Move的一些用法:
?
以下是alter table 中move子句的完整語(yǔ)法,我們介紹其中的幾點(diǎn):
?
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將一個(gè)table從當(dāng)前的tablespace上移動(dòng)到另一個(gè)tablespace上,如:
?
alter table t move tablespace tablespace_name;
?
b. 我們還可以用move來(lái)改變table已有的block的存儲(chǔ)參數(shù),如:
?
alter table t move storage (initial 30k next 50k);
?
c.另外,move操作也可以用來(lái)解決table中的行遷移的問(wèn)題。
?
?
使用move的一些注意事項(xiàng):
?
a. table上的index需要rebuild:
?
在前面我們討論過(guò),move操作后,數(shù)據(jù)的rowid發(fā)生了改變,我們知道,index是通過(guò)rowid來(lái)fetch數(shù)據(jù)行的,所以,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
?
從這里可以看到,當(dāng)table MY_OBJECTS進(jìn)行move操作后,該table 上的inedx的狀態(tài)為UNUSABLE,這時(shí),我們可以使用alter index I_MY_OBJECTS rebuild online的命令,對(duì)index I_MY_OBJECTS進(jìn)行在線rebuild。
?
b. move時(shí)對(duì)table的鎖定
?
當(dāng)我們對(duì)table MY_OBJECTS進(jìn)行move操作時(shí),查詢v$locked_objects視圖可以發(fā)現(xiàn),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在進(jìn)行move操作時(shí),我們只能對(duì)它進(jìn)行select的操作。反過(guò)來(lái)說(shuō),當(dāng)我們的一個(gè)session對(duì)table進(jìn)行DML操作且沒(méi)有commit時(shí),在另一個(gè)session中是不能對(duì)這個(gè)table進(jìn)行move操作的,否則oracle會(huì)返回這樣的錯(cuò)誤信息:ORA-00054: 資源正忙,要求指定 NOWAIT。
?
c. 關(guān)于move時(shí)空間使用的問(wèn)題:
?
當(dāng)我們使用alter table move來(lái)降低table的HWM時(shí),有一點(diǎn)是需要注意的,這時(shí),當(dāng)前的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;
?
表已創(chuàng)建。
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: 無(wú)法通過(guò)16(在表空間TEST1中)擴(kuò)展 temp 段
SQL> ALTER DATABASE
?2? DATAFILE 'D:\ORACLE\ORADATA\ORACLE9I\TEST1.DBF' RESIZE 7M;
數(shù)據(jù)庫(kù)已更改。
SQL> alter table MY_OBJECTS move;
表已更改。
?