分区表使用ENABLE ROW MOVEMENT的副作用 [转帖]_MySQL, Oracle及数据库讨论区_Weblogic技术|Tuxedo技术|中间件技术|Oracle论坛|JAVA论坛|Linux/Unix技术|hadoop论坛_联动北方技术论坛  
网站首页 | 关于我们 | 服务中心 | 经验交流 | 公司荣誉 | 成功案例 | 合作伙伴 | 联系我们 |
联动北方-国内领先的云技术服务提供商
»  游客             当前位置:  论坛首页 »  自由讨论区 »  MySQL, Oracle及数据库讨论区 »
总帖数
1
每页帖数
101/1页1
返回列表
0
发起投票  发起投票 发新帖子
查看: 4355 | 回复: 0   主题: 分区表使用ENABLE ROW MOVEMENT的副作用 [转帖]        下一篇 
wayne
注册用户
等级:中校
经验:1690
发帖:221
精华:0
注册:2011-7-21
状态:离线
发送短消息息给wayne 加好友    发送短消息息给wayne 发消息
发表于: IP:您无权察看 2011-8-16 14:26:16 | [全部帖] [楼主帖] 楼主

一般情况下,分区表的分区字段的值是不应该修改的,如果这个值发生变化,则有可能使这条记录不再符号当前分区的分区条件,会使这条记录转移到其他分区中,物理位置(ROWID)会相应变化。

Oracle提供了ENABLE ROW MOVEMENT语句,增加了分区的功能,允许修改分区列,允许记录转移到其他分区,且Oracle会自动维护索引。

虽然,Oracle提供的这个功能很方便,但是也会带来相应的副作用——ROWID不可避免的要发生变化。其中最直接的影响就是LOGMINER,这种发生了ENABLE ROW MOVEMENT的操作,将无法使用LOGMINER中的SQL_UNDO来进行恢复。

具体情况来看下面的例子:

SQL> CREATE TABLE TEST_PART (ID NUMBER) PARTITION BY RANGE (ID)
2  (PARTITION P1 VALUES LESS THAN (100), PARTITION P2 VALUES LESS THAN (MAXVALUE))
3  ENABLE ROW MOVEMENT;


表已创建。

SQL> INSERT INTO TEST_PART VALUES (20);


已创建 1 行。

SQL> INSERT INTO TEST_PART VALUES (20);


已创建 1 行。

SQL> COMMIT;


提交完成。

SQL> COL MEMBER FORMAT A70
SQL> SELECT * FROM V$LOGFILE;
GROUP# STATUS  TYPE    MEMBER
---------- ------- ------- ---------------------------------------
3 STALE   ONLINE  F:ORACLEORADATATEST4REDO03.LOG
2 STALE   ONLINE  F:ORACLEORADATATEST4REDO02.LOG
1         ONLINE  F:ORACLEORADATATEST4REDO01.LOG
SQL> ALTER SYSTEM SWITCH LOGFILE;


系统已更改。

SQL> SELECT * FROM V$LOGFILE;
GROUP# STATUS  TYPE    MEMBER
---------- ------- ------- ----------------------------------------
3 STALE   ONLINE  F:ORACLEORADATATEST4REDO03.LOG
2         ONLINE  F:ORACLEORADATATEST4REDO02.LOG
1         ONLINE  F:ORACLEORADATATEST4REDO01.LOG
SQL> UPDATE TEST_PART SET ID = 120 WHERE ROWNUM = 1;


已更新 1 行。

SQL> COMMIT;


提交完成。

SQL> ALTER SYSTEM SWITCH LOGFILE;


系统已更改。

SQL> SELECT * FROM V$LOGFILE;
GROUP# STATUS  TYPE    MEMBER
---------- ------- ------- --------------------------------------
3         ONLINE  F:ORACLEORADATATEST4REDO03.LOG
2         ONLINE  F:ORACLEORADATATEST4REDO02.LOG
1         ONLINE  F:ORACLEORADATATEST4REDO01.LOG
SQL> EXEC SYS.DBMS_LOGMNR.ADD_LOGFILE(LOGFILENAME => 'F:ORACLEORADATATEST4REDO02.LOG', -
> OPTIONS => SYS.DBMS_LOGMNR.NEW)


PL/SQL 过程已成功完成。

SQL> EXEC SYS.DBMS_LOGMNR.START_LOGMNR(OPTIONS => SYS.DBMS_LOGMNR.DICT_FROM_ONLINE_CATALOG)


PL/SQL 过程已成功完成。

SQL> SELECT SQL_UNDO, SQL_REDO FROM V$LOGMNR_CONTENTS;
SQL_UNDO
------------------------------------------------------------------
SQL_REDO
------------------------------------------------------------------
set transaction read write;
update "YANGTK"."TEST_PART" set "ID" = '20' where "ID" = '120' and ROWID = 'AAAB5OAAFAAAAegAAA';
update "YANGTK"."TEST_PART" set "ID" = '120' where "ID" = '20' and ROWID = 'AAAB5OAAFAAAAegAAA';
insert into "YANGTK"."TEST_PART"("ID") values ('120');
delete from "YANGTK"."TEST_PART" where "ID" = '120' and ROWID = 'AAAB5OAAFAAAAegAAA';
delete from "YANGTK"."TEST_PART" where "ID" = '120' and ROWID = 'AAAB5PAAFAAAAeoAAA';
insert into "YANGTK"."TEST_PART"("ID") values ('120');
commit;
SQL> exec sys.dbms_logmnr.end_logmnr


PL/SQL 过程已成功完成。

SQL> delete from "YANGTK"."TEST_PART" where "ID" = '120' and ROWID = 'AAAB5PAAFAAAAeoAAA';


已删除 1 行。

SQL> insert into "YANGTK"."TEST_PART"("ID") values ('120');


已创建 1 行。

SQL> update "YANGTK"."TEST_PART" set "ID" = '20' where "ID" = '120' and ROWID = 'AAAB5OAAFAAAAegAAA';


已更新0行。

可以看到,一个UPDATE语句被ORACLE拆成了三条语句。首先是对当前的记录进行更新(指定ROWID),第二步删除指定ROWID的记录,第三步用更新后的值重新插入记录。执行完第三步,新的记录已经插入到分区P2中了。

如果按照相反的顺序执行SQL_UNDO,却发现无法恢复到以前的状态。首先删除分区P2中的记录,这没有问题。第二步,插入新的记录,这里已经有问题了,插入时无法指定ROWID,记录仍然会插入到P2分区中。最后进行更新,这是指定的ROWID是P1分区中的ROWID,这个ROWID在当前根本就不存在,因此,已经无法恢复到原来的状态了。




赞(0)    操作        顶端 
总帖数
1
每页帖数
101/1页1
返回列表
发新帖子
请输入验证码: 点击刷新验证码
您需要登录后才可以回帖 登录 | 注册
技术讨论