今天上午我一个同事误truncate了一个表uplbth,她问我是否可以恢复?
我们先去看一下这个表现在的状况:
SQL> select owner,object_name,object_id,data_object_id from dba_objects where object_name='UPLBTH';
OWNER OBJECT_NAME OBJECT_ID DATA_OBJECT_ID
------------------------------ --------------- ---------- --------------
CAIPRA UPLBTH 52210 95137
从结果里我们可以看到,这个表的data object id已经比其object id大了太多,极有可能是曾经被多次truncate过。
后来我问了一下她是否多次truncate过这个表,她说是。然后我对她说,你等我信儿吧。
熊哥曾经在"使用ODU恢复Truncate表"这篇文章里提到了如何确定被多次truncate后的data object id,我这里用另外一种方式来精确定位我要恢复的data object id。
利用的原理就是:oracle里有system回滚段,而oracle对数据字典的操作基本上是DML,既然是DML,那就好办了,我们有很大的概率可以成功执行flashback query。
回到刚才的例子,我首先从dba_objects里知道了uplbth的last_ddl_time是2010-2-3 10:18:57;接着,我们直接执行flashback query来确定在执行truncate操作的那个时间点之前uplbth的data object id:
SQL> select owner,object_name,object_id,data_object_id from dba_objects as of timestamp to_timestamp('2010-02-03 10:18:00','YYYY-MM-DD HH24:MI:SS') where object_name='UPLBTH';
OWNER OBJECT_NAME OBJECT_ID DATA_OBJECT_ID
------------------------------ --------------- ---------- --------------
CAIPRA UPLBTH 52210 77675
可以看到,当时的data object id是77675,精确的确定了data object id后,剩下的事情就都交给ODU好了:
ODU> unload table caipra.uplbth object 77675
Unloading table: UPLBTH,object ID: 52210
Unloading segment,storage(Obj#=52210 DataObj#=77675 TS#=16 File#=15 Block#=18828 Cluster=0)
1888 rows unloaded
可以看到,我们成功恢复出来了1880条数据。
nice