Oracle 行遷移詳解
阿新 • • 發佈:2018-12-16
行遷移 英文的意思是 Row movement
預設情況下,oracle資料塊中的一行其生命週期內是不會發生移動的,即塊的rowid不會發生改變. 但是在某些情景下,我們希望行的rowid可以發生變化,這時候我們就需要啟動表的row movement特性。
啟用row movement特性,使用如下語句:
Alter table table_name enable row movement;
通常在三種情景下,需要啟用row movement。
1:分割槽表
當我們允許分割槽表的分割槽鍵是可更新的時候,如果分割槽鍵的更新導致當前修改的資料條目需要移動到其他分割槽,
此時就會發生rowid的改變。
SQL> create table test_jack(id number,quantity varchar2(10))
2 partition by list(quantity)
3 (
4 partition p1 values('1'),
5 partition p2 values('2'),
6 partition p3 values('3'));
Table created.
SQL> insert into test_jack values(1,'1');
1 row created.
SQL> insert into test_jack values(2,'2');
1 row created.
SQL> insert into test_jack values(3,'3');
1 row created.
SQL> insert into test_jack values(4,'1');
1 row created.
SQL> commit;
Commit complete.
SQL> select * from test_jack partition(p1);
id quantity
------------- ----------
1 1
4 1
SQL> select * from test_jack partition(p2);
id quantity
------------- ----------
2 2
SQL> update test_jack set quantity=2 where id=4;
update test_jack set quantity=2 where id=4
*
ERROR at line 1:
ORA-14402: updating partition key column would cause a partition change
SQL> alter table test_jack enable row movement;
Table altered.
SQL> update test_jack set quantity=2 where id=4;
1 row updated.
SQL> select * from test_jack partition(p1);
id quantity
------------- ----------
1 1
SQL> select * from test_jack partition(p2);
id quantity
------------- ----------
2 2
4 2
2:閃回操作
在閃回操作時,我們同樣需要開啟表的row movement特性。
SQL> alter table test_jack disable row movement;
Table altered.
SQL> select current_scn from v$database;
CURRENT_SCN
-----------
1633927
SQL> select count(*) from test_jack;
COUNT(*)
----------
4
SQL> delete from test_jack where quantity=1;
1 row deleted.
SQL> commit;
Commit complete.
SQL> flashback table test_jack to scn 1633927;
flashback table test_jack to scn 1633927
*
ERROR at line 1:
ORA-08189: cannot flashback the table because row movement is not enabled
SQL> alter table test_jack enable row movement;
Table altered.
SQL> flashback table test_jack to scn 1633927;
Flashback complete.
SQL> select count(*) from test_jack;
COUNT(*)
----------
4
為什麼flashback table會造成rowid的改變呢?通過下面的實驗來研究一下:
SQL> create table hh(id number);
Table created.
SQL> insert into hh values(1);
1 row created.
SQL> commit;
Commit complete.
SQL> alter table hh enable row movement;
Table altered.
SQL> select current_scn from v$database;
CURRENT_SCN
-----------
1635103
SQL> update table hh set id = 2;
update table hh set id = 2
*
ERROR at line 1:
ORA-00903: invalid table name
SQL> update hh set id = 2;
1 row updated.
SQL> commit;
Commit complete.
SQL> alter session set tracefile_identifier = 'ee';
Session altered.
SQL> alter session set sql_trace=true;
Session altered.
SQL> flashback table hh to scn 1635103;
Flashback complete.
通過檢視trace檔案,我們可以發現oracle flashback table 是通過一個臨時表sys_temp_fbt來實現的。trace檔案中的部分內容如下:
********************************************************************************
sqlid='dtjmzuugu6ktw'
INSERT /*+ APPEND */ into SYS_TEMP_FBT SELECT /*+ FBTSCAN FULL(S) PARALLEL(S, DEFAULT) */ :1, :2, :3, rowid, SYS_FBT_INSDEL FROM "QIANXUN"."HH" as of SCN :4 S
********************************************************************************
sqlid='bytpvbcb8zbb6'
/* Flashback Table */ DELETE /*+ BYPASS_UJVC */ FROM (SELECT /*+ ORDERED USE_NL(S) PARALLEL(S,DEFAULT) PARALLEL(T,DEFAULT) */ S.rowid FROM SYS_TEMP_FBT T, "QIANXUN"."HH" S WHERE T.rid = S.rowid and T.action = 'D' and T.object# = : 1) V
********************************************************************************
sqlid='a3h5cbfc5b6xv'
/* Flashback Table */ INSERT /*+ PARALLEL(S, DEFAULT) PARALLEL(T, DEFAULT) */ INTO "QIANXUN"."HH" SELECT /*+ USE_NL(S) ORDERED PARALLEL(S, DEFAULT) PARALLEL(T, DEFAULT) */ S.* FROM SYS_TEMP_FBT T , "QIANXUN"."HH" as of SCN :1 S WHERE T.rid = S.rowid and T.action = 'I' and T.object# = :2
由此可見,oracle是通過SYS_TEMP_FBT進行刪除操作,而後進行插入操作,因此行的rowid有可能發生改變、
SQL> select * from sys_temp_fbt ;
SCHEMA OBJECT_NAME OBJECT# RID A
---------- -------------------- ---------- ------------------------------ -
hh hh 76906 AAASxqAAGAAAAC0AAA D
hh hh 76906 AAASxqAAGAAAAC0AAA I
SQL> select tname,tabtype from tab;
TNAME TABTYPE
------------------------------ -------
HH TABLE
SYS_TEMP_FBT TABLE
TEST_JACK TABLE
SQL> ALTER TABLE test_jackS ENABLE ROW MOVEMENT;
Table altered.
SQL> FLASHBACK TABLE test_jackS TO TIMESTAMP (SYSTIMESTAMP - INTERVAL '06' minute);
Flashback complete.
SQL> SELECT * FROM test_jackS;
id quantity OFFICE_NAME
------------- ------------ ------------------------------
1 282 DENVER
2 282 DENVER TECH CTR
3 282 DENVER WEST
4 283 BROOMFIELD
如果表的行移動禁用了,為什麼可以在沒有行移動的情況下刪除表並將表返回到沒有行移動的情況下?
下面讓我們演示一遍 用行遷移恢復,通過上面的例子 可能你已經有答案了。
SQL> ALTER TABLE test_jackS DISABLE ROW MOVEMENT;
Table altered.
SQL> DROP TABLE test_jackS;
Table dropped.
SQL> FLASHBACK TABLE test_jackS TO BEFORE DROP;
Flashback complete.
沒錯,因為drop表Oracle有另外的回收站技術恢復過來,而刪除幾行記錄是不能 直接通過回收站恢復的。
3:回收空間
在收縮空間時,也會造成行的移動,如下
SQL> alter table hh disable row movement;
Table altered.
SQL> alter table hh shrink space;
alter table hh shrink space
*
ERROR at line 1:
ORA-10636: ROW MOVEMENT is not enabled
SQL> alter table hh enable row movement;
Table altered.
SQL> alter table hh shrink space;
Table altered.
Shrink space操作(without compact)會導致所有已經開啟的遊標失效,因此需要謹慎使用!
預設情況下,oracle資料塊中的一行其生命週期內是不會發生移動的,即塊的rowid不會發生改變. 但是在某些情景下,我們希望行的rowid可以發生變化,這時候我們就需要啟動表的row movement特性。
啟用row movement特性,使用如下語句:
Alter table table_name enable row movement;
通常在三種情景下,需要啟用row movement。
1:分割槽表
當我們允許分割槽表的分割槽鍵是可更新的時候,如果分割槽鍵的更新導致當前修改的資料條目需要移動到其他分割槽,
此時就會發生rowid的改變。
SQL> create table test_jack(id number,quantity varchar2(10))
2 partition by list(quantity)
3 (
4 partition p1 values('1'),
5 partition p2 values('2'),
6 partition p3 values('3'));
Table created.
SQL> insert into test_jack values(1,'1');
1 row created.
SQL> insert into test_jack values(2,'2');
1 row created.
SQL> insert into test_jack values(3,'3');
1 row created.
SQL> insert into test_jack values(4,'1');
1 row created.
SQL> commit;
Commit complete.
SQL> select * from test_jack partition(p1);
id quantity
------------- ----------
1 1
4 1
SQL> select * from test_jack partition(p2);
id quantity
------------- ----------
2 2
SQL> update test_jack set quantity=2 where id=4;
update test_jack set quantity=2 where id=4
*
ERROR at line 1:
ORA-14402: updating partition key column would cause a partition change
SQL> alter table test_jack enable row movement;
Table altered.
SQL> update test_jack set quantity=2 where id=4;
1 row updated.
SQL> select * from test_jack partition(p1);
id quantity
------------- ----------
1 1
SQL> select * from test_jack partition(p2);
id quantity
------------- ----------
2 2
4 2
2:閃回操作
在閃回操作時,我們同樣需要開啟表的row movement特性。
SQL> alter table test_jack disable row movement;
Table altered.
SQL> select current_scn from v$database;
CURRENT_SCN
-----------
1633927
SQL> select count(*) from test_jack;
COUNT(*)
----------
4
SQL> delete from test_jack where quantity=1;
1 row deleted.
SQL> commit;
Commit complete.
SQL> flashback table test_jack to scn 1633927;
flashback table test_jack to scn 1633927
*
ERROR at line 1:
ORA-08189: cannot flashback the table because row movement is not enabled
SQL> alter table test_jack enable row movement;
Table altered.
SQL> flashback table test_jack to scn 1633927;
Flashback complete.
SQL> select count(*) from test_jack;
COUNT(*)
----------
4
為什麼flashback table會造成rowid的改變呢?通過下面的實驗來研究一下:
SQL> create table hh(id number);
Table created.
SQL> insert into hh values(1);
1 row created.
SQL> commit;
Commit complete.
SQL> alter table hh enable row movement;
Table altered.
SQL> select current_scn from v$database;
CURRENT_SCN
-----------
1635103
SQL> update table hh set id = 2;
update table hh set id = 2
*
ERROR at line 1:
ORA-00903: invalid table name
SQL> update hh set id = 2;
1 row updated.
SQL> commit;
Commit complete.
SQL> alter session set tracefile_identifier = 'ee';
Session altered.
SQL> alter session set sql_trace=true;
Session altered.
SQL> flashback table hh to scn 1635103;
Flashback complete.
通過檢視trace檔案,我們可以發現oracle flashback table 是通過一個臨時表sys_temp_fbt來實現的。trace檔案中的部分內容如下:
********************************************************************************
sqlid='dtjmzuugu6ktw'
INSERT /*+ APPEND */ into SYS_TEMP_FBT SELECT /*+ FBTSCAN FULL(S) PARALLEL(S, DEFAULT) */ :1, :2, :3, rowid, SYS_FBT_INSDEL FROM "QIANXUN"."HH" as of SCN :4 S
********************************************************************************
sqlid='bytpvbcb8zbb6'
/* Flashback Table */ DELETE /*+ BYPASS_UJVC */ FROM (SELECT /*+ ORDERED USE_NL(S) PARALLEL(S,DEFAULT) PARALLEL(T,DEFAULT) */ S.rowid FROM SYS_TEMP_FBT T, "QIANXUN"."HH" S WHERE T.rid = S.rowid and T.action = 'D' and T.object# = : 1) V
********************************************************************************
sqlid='a3h5cbfc5b6xv'
/* Flashback Table */ INSERT /*+ PARALLEL(S, DEFAULT) PARALLEL(T, DEFAULT) */ INTO "QIANXUN"."HH" SELECT /*+ USE_NL(S) ORDERED PARALLEL(S, DEFAULT) PARALLEL(T, DEFAULT) */ S.* FROM SYS_TEMP_FBT T , "QIANXUN"."HH" as of SCN :1 S WHERE T.rid = S.rowid and T.action = 'I' and T.object# = :2
由此可見,oracle是通過SYS_TEMP_FBT進行刪除操作,而後進行插入操作,因此行的rowid有可能發生改變、
SQL> select * from sys_temp_fbt ;
SCHEMA OBJECT_NAME OBJECT# RID A
---------- -------------------- ---------- ------------------------------ -
hh hh 76906 AAASxqAAGAAAAC0AAA D
hh hh 76906 AAASxqAAGAAAAC0AAA I
SQL> select tname,tabtype from tab;
TNAME TABTYPE
------------------------------ -------
HH
SYS_TEMP_FBT TABLE
TEST_JACK TABLE
SQL> ALTER TABLE test_jackS ENABLE ROW MOVEMENT;
Table altered.
SQL> FLASHBACK TABLE test_jackS TO TIMESTAMP (SYSTIMESTAMP - INTERVAL '06' minute);
Flashback complete.
SQL> SELECT * FROM test_jackS;
id quantity OFFICE_NAME
------------- ------------ ------------------------------
1 282 DENVER
2 282 DENVER TECH CTR
3 282 DENVER WEST
4 283 BROOMFIELD
如果表的行移動禁用了,為什麼可以在沒有行移動的情況下刪除表並將表返回到沒有行移動的情況下?
下面讓我們演示一遍 用行遷移恢復,通過上面的例子 可能你已經有答案了。
SQL> ALTER TABLE test_jackS DISABLE ROW MOVEMENT;
Table altered.
SQL> DROP TABLE test_jackS;
Table dropped.
SQL> FLASHBACK TABLE test_jackS TO BEFORE DROP;
Flashback complete.
沒錯,因為drop表Oracle有另外的回收站技術恢復過來,而刪除幾行記錄是不能 直接通過回收站恢復的。
3:回收空間
在收縮空間時,也會造成行的移動,如下
SQL> alter table hh disable row movement;
Table altered.
SQL> alter table hh shrink space;
alter table hh shrink space
*
ERROR at line 1:
ORA-10636: ROW MOVEMENT is not enabled
SQL> alter table hh enable row movement;
Table altered.
SQL> alter table hh shrink space;
Table altered.
Shrink space操作(without compact)會導致所有已經開啟的遊標失效,因此需要謹慎使用!