今天在跟朋友讨论了如下话题:


《有一张表上建立索引,DROP该表,又闪回删除回来,请问,这张表上的索引还能用吗?如果有变化那是什么?》


我进行了如下测试:


sys@MAA> select * from v$version;


BANNER

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

Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production

PL/SQL Release 11.2.0.3.0 - Production

CORE    11.2.0.3.0      Production

TNS for Linux: Version 11.2.0.3.0 - Production

NLSRTL Version 11.2.0.3.0 - Production


-- 我的TEST2表上有两个索引

luocs@MAA> select index_name, status from user_indexes where table_name='TEST2';


INDEX_NAME                                                   STATUS

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

INX_TEST2_ZH                                                 VALID

INX_TEST2                                                    VALID


luocs@MAA> set autot trace exp stat

luocs@MAA> select count(*) from test2 where id=1;


Execution Plan

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

Plan hash value: 3565898414


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

| Id  | Operation         | Name         | Rows  | Bytes | Cost (%CPU)| Time     |

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

|   0 | SELECT STATEMENT  |              |     1 |     5 |     2   (0)| 00:00:01 |

|   1 |  SORT AGGREGATE   |              |     1 |     5 |            |          |

|*  2 |   INDEX RANGE SCAN| INX_TEST2_ZH |     2 |    10 |     2   (0)| 00:00:01 |

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


Predicate Information (identified by operation id):

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


2 - access("ID"=1)


Statistics

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

         1  recursive calls

         0  db block gets

         2  consistent gets

         0  physical reads

         0  redo size

       525  bytes sent via SQL*Net to client

       523  bytes received via SQL*Net from client

         2  SQL*Net roundtrips to/from client

         0  sorts (memory)

         0  sorts (disk)

         1  rows processed


-- DROP 表TEST2

luocs@MAA> drop table test2;


Table dropped.


-- 索引也被删除

luocs@MAA> select index_name, status from user_indexes where table_name='TEST2';


no rows selected


-- 这时候查看回收站,我们看到表的删除记录,却没有看到索引的

luocs@MAA> show recyclebin

ORIGINAL NAME    RECYCLEBIN NAME                OBJECT TYPE  DROP TIME

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

TEST2            BIN$048hXdZTf0HgQwEAAH/4UQ==$0 TABLE        2013-01-18:19:20:06


-- 进行闪回删除

luocs@MAA> flashback table test2 to before drop;


Flashback complete.


-- 这时候又能看到索引信息,也是可用状态,却索引名称改变,依然使用回收站里的名字

luocs@MAA> select index_name, status from user_indexes where table_name='TEST2';


INDEX_NAME                                                   STATUS

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

BIN$048hXdZSf0HgQwEAAH/4UQ==$0                               VALID

BIN$048hXdZRf0HgQwEAAH/4UQ==$0                               VALID


-- 我们也看到该索引能够正常使用

luocs@MAA> set autot trace exp

luocs@MAA> select count(*) from test2 where id=1;


Execution Plan

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

Plan hash value: 3980542661


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

| Id  | Operation         | Name                           | Rows  | Bytes | Cost (%CPU)| Time     |

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

|   0 | SELECT STATEMENT  |                                |     1 |     5 |     2   (0)| 00:00:01 |

|   1 |  SORT AGGREGATE   |                                |     1 |     5 |            |          |

|*  2 |   INDEX RANGE SCAN| BIN$048hXdZSf0HgQwEAAH/4UQ==$0 |     2 |    10 |     2   (0)| 00:00:01 |

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


Predicate Information (identified by operation id):

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


2 - access("ID"=1)


-- 我们可以RENAME索引名字以恢复

luocs@MAA> alter index "BIN$048hXdZSf0HgQwEAAH/4UQ==$0" rename to inx_test2_zh;


Index altered.


luocs@MAA> alter index "BIN$048hXdZRf0HgQwEAAH/4UQ==$0" rename to inx_test2;


Index altered.


luocs@MAA> select index_name, status from user_indexes where table_name='TEST2';


INDEX_NAME                                                   STATUS

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

INX_TEST2_ZH                                                 VALID

INX_TEST2                                                    VALID


因此,在表被DROP掉后,索引也被放到回收站里,再我们flashback drop之后,索引也被还原,也能正常使用,但索引名却没有还原过来。


那这里有个问题存在,既然索引页被放到回收站里,为什么执行show recyclebin的时候没有看到索引信息?


OK,我通过如下方式解释:


-- 通过10046事件分析下show recyclebin到底干了什么

luocs@MAA> alter session set events '10046 trace name context forever, level 8';


Session altered.


luocs@MAA> show recyclebin


luocs@MAA> alter session set events '10046 trace name context off';


Session altered.


luocs@MAA> select value from v$diag_info where name = 'Default Trace File';


VALUE

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

/u01/app/oracle/diag/rdbms/maa/maa/trace/maa_ora_32580.trc


-- 我在TRACE内容里找到如下语句,这里重点看WHERE子句CAN_UNDROP='YES'

SELECT ORIGINAL_NAME ORIGNAME_PLUS_SHOW_RECYC,OBJECT_NAME

 OBJECTNAME_PLUS_SHOW_RECYC,TYPE OBJTYPE_PLUS_SHOW_RECYC,DROPTIME

 DROPTIME_PLUS_SHOW_RECYC

FROM

USER_RECYCLEBIN WHERE CAN_UNDROP='YES' ORDER BY ORIGINAL_NAME,DROPTIME DESC,

 OBJECT_NAME


-- 这里CAN_UNDROP='YES' 起到作用了


-- 我们看一下recyclebin$表创建语法与注释信息(Oracle 11g开始recyclebin$表创建语句在dsqlddl.bsq脚本里,位于$ORACLE_HOME/rdbms/admin)

create table recyclebin$

(

 obj#                  number not null,           /* original object number */

 owner#                number not null,                /* owner user number */

 original_name         varchar2(32),                /* Original Object Name */

 operation             number not null,            /* Operation carried out */

                                                               /* 0 -> DROP */

                                           /* 1 -> TRUNCATE (not supported) */

 type#                 number not null,          /* object type (see KQD.H) */

 ts#                   number,                         /* tablespace number */

 file#                 number,                /* segment header file number */

 block#                number,               /* segment header block number */

 droptime              date,                /* time when object was dropped */

 dropscn               number,           /* SCN of Tx which caused the drop */

 partition_name        varchar2(32),       /* Name of the partition dropped */

                                                          /* NULL otherwise */

 flags                 number,               /* flags for undrop processing */

 related               number not null,    /* obj one level up in heirarchy */

 bo                    number not null,                      /* base object */

 purgeobj              number not null,   /* obj to purge when purging this */

 base_ts#              number,            /* Base objects Tablespace number */

 base_owner#           number,                 /* Base objects owner number */

 space                 number,       /* number of blocks used by the object */

 con#                  number,       /* con#, if index is due to constraint */

 spare1                number,

 spare2                number,

 spare3                number

)

/


-- 其中flags的注释内容是flags for undrop processing,我们可以查这张表,然后查看表和索引对应的flags分别多少


-- 再drop 表test2,然后查看recyclebin$表

sys@MAA> select USER_ID, USERNAME from dba_users where USERNAME='LUOCS';


USER_ID USERNAME

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

       51 LUOCS


sys@MAA> select OBJ#, OWNER#, TYPE#, OPERATION, DROPTIME, DROPSCN, FLAGS from recyclebin$ where OWNER#=51;


OBJ#     OWNER#      TYPE#  OPERATION DROPTIME                   DROPSCN      FLAGS

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

    24248         51          2          0 18-JAN-2013 21:02:24       1134044         18

    24352         51          2          0 18-JAN-2013 21:02:24       1134047         18

    24247         51          1          0 18-JAN-2013 21:02:24       1134051         30

-- 可知表对应的flags为30,索引对应的flags为18。另外,OBJ#为DROP对象前的对象编号,这个在下面闪回删除之后再证明


OK 有点跑偏了。


-- 我们通过10046分析出show recyclebin其实是执行下面一段SQL语句:

SELECT ORIGINAL_NAME ORIGNAME_PLUS_SHOW_RECYC,OBJECT_NAME

 OBJECTNAME_PLUS_SHOW_RECYC,TYPE OBJTYPE_PLUS_SHOW_RECYC,DROPTIME

 DROPTIME_PLUS_SHOW_RECYC

FROM

USER_RECYCLEBIN WHERE CAN_UNDROP='YES' ORDER BY ORIGINAL_NAME,DROPTIME DESC,

 OBJECT_NAME


-- 我们将CAN_UNDROP='YES'去掉,然后执行:

luocs@MAA> SELECT ORIGINAL_NAME ORIGNAME_PLUS_SHOW_RECYC,OBJECT_NAME

 2    OBJECTNAME_PLUS_SHOW_RECYC,TYPE OBJTYPE_PLUS_SHOW_RECYC,DROPTIME

 3    DROPTIME_PLUS_SHOW_RECYC

 4  FROM

 5   USER_RECYCLEBIN ORDER BY ORIGINAL_NAME,DROPTIME DESC,

 6    OBJECT_NAME

 7  /


ORIGINAL NAME    RECYCLEBIN NAME                OBJECT TYPE  DROP TIME

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

INX_TEST2        BIN$05C5BoYUf0TgQwEAAH+5aw==$0 INDEX        2013-01-18:21:02:24

INX_TEST2_ZH     BIN$05C5BoYVf0TgQwEAAH+5aw==$0 INDEX        2013-01-18:21:02:24

TEST2            BIN$05C5BoYWf0TgQwEAAH+5aw==$0 TABLE        2013-01-18:21:02:24

-- 从这里我们也获得了原对象名以及回收站里的对象名,因此RENAME的时候可以找对对象。


-- 将CAN_UNDROP 设置为 'NO'再执行:

luocs@MAA> SELECT ORIGINAL_NAME ORIGNAME_PLUS_SHOW_RECYC,OBJECT_NAME

 2    OBJECTNAME_PLUS_SHOW_RECYC,TYPE OBJTYPE_PLUS_SHOW_RECYC,DROPTIME

 3    DROPTIME_PLUS_SHOW_RECYC

 4  FROM

 5   USER_RECYCLEBIN WHERE CAN_UNDROP='NO' ORDER BY ORIGINAL_NAME,DROPTIME DESC,

 6    OBJECT_NAME

 7  /


ORIGINAL NAME    RECYCLEBIN NAME                OBJECT TYPE  DROP TIME

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

INX_TEST2        BIN$05C5BoYUf0TgQwEAAH+5aw==$0 INDEX        2013-01-18:21:02:24

INX_TEST2_ZH     BIN$05C5BoYVf0TgQwEAAH+5aw==$0 INDEX        2013-01-18:21:02:24


-- 进行flashback drop

luocs@MAA> flashback table test2 to before drop;


Flashback complete.


-- 再查询已经看不到内容了

luocs@MAA> SELECT ORIGINAL_NAME ORIGNAME_PLUS_SHOW_RECYC,OBJECT_NAME

 2    OBJECTNAME_PLUS_SHOW_RECYC,TYPE OBJTYPE_PLUS_SHOW_RECYC,DROPTIME

 3    DROPTIME_PLUS_SHOW_RECYC

 4  FROM

 5   USER_RECYCLEBIN ORDER BY ORIGINAL_NAME,DROPTIME DESC,

 6    OBJECT_NAME

 7  /


no rows selected


-- 根据上面获得的对象编号来查看对象名字

sys@MAA> col OBJECT_NAME for a30

sys@MAA> col OWNER for a30

sys@MAA> select OBJECT_NAME, OWNER from dba_objects where OBJECT_ID IN ('24248','24352','24247');


OBJECT_NAME                    OWNER

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

BIN$048hXdZVf0HgQwEAAH/4UQ==$1 LUOCS

BIN$048hXdZUf0HgQwEAAH/4UQ==$1 LUOCS

TEST2                          LUOCS


oracle视频教程请关注:http://u.youku.com/user_video/id_UMzAzMjkxMjE2.html