【實戰】使用“基表修改法”恢復被“set unused”方式誤刪除的列
在《【實驗】列刪除的一些細節探索》http://space.itpub.net/519536/viewspace-616123中談到了可以透過手工修改tab$ col$基表的方式對被“set unused”方式誤刪除的列進行恢復。
透過這個文章,我來給大家深入的演示一下這個極端的恢復過程,供參考。
文中為了展示全貌,有一些不可迴避的換行,影響了顯示效果,如果您有深入研究的興趣,可以將這篇文章複製到Ultraedit中並使用“Ctrl+W”調整折行模式進行研究比較。
1.建立實驗用測試表t,並初始化資料
sec@ora10g> create table t (x number, y number);
sec@ora10g> insert into t values (1,1);
sec@ora10g> insert into t values (2,2);
sec@ora10g> insert into t values (3,3);
sec@ora10g> commit;
2.檢視錶結構和測試資料
sec@ora10g> desc t;
Name Null? Type
---------- -------- ------------
X NUMBER
Y NUMBER
sec@ora10g> select * from t;
X Y
---------- ----------
1 1
2 2
3 3
3.檢視四個檢視中關於t表的定義資訊
1)檢視dba_objects檢視(為清晰的顯示,SQL*Plus下要做精心的格式化)
sys@ora10g> col OWNER for a5
sys@ora10g> col OBJECT_NAME for a11
sys@ora10g> col SUBOBJECT_NAME for a3
sys@ora10g> col OBJECT_TYPE for a11
sys@ora10g> select * from dba_objects where object_name = 'T' and wner = 'SEC';
OWNER OBJECT_NAME SUB OBJECT_ID DATA_OBJECT_ID OBJECT_TYPE CREATED LAST_DDL_TIME TIMESTAMP STATUS T G S
----- ----------- --- ---------- -------------- ----------- ------------------- ------------------- ------------------- ------- - - -
SEC T 16416 16416 TABLE 2009-10-09 08:18:59 2009-10-09 08:18:59 2009-10-09:08:18:59 VALID N N N
2)檢視obj$檢視(為清晰的顯示,SQL*Plus下要做精心的格式化)
sys@ora10g> set lines 2000
sys@ora10g> col OBJ# for 99999
sys@ora10g> col DATAOBJ# for 99999
sys@ora10g> col name for a4
sys@ora10g> col SUBNAME for a7
sys@ora10g> col TYPE# for 99
sys@ora10g> col REMOTEOWNER for a11
sys@ora10g> col LINKNAME for a8
sys@ora10g> col FLAGS for 99
sys@ora10g> col OID$ for a4
sys@ora10g> col SPARE1 for 99
sys@ora10g> col SPARE2 for 99
sys@ora10g> col SPARE3 for 999
sys@ora10g> col SPARE4 for a6
sys@ora10g> col SPARE5 for a6
sys@ora10g> col SPARE6 for a6
sys@ora10g> select * from obj$ where name = 'T';
OBJ# DATAOBJ# OWNER# NAME NAMESPACE SUBNAME TYPE# CTIME MTIME STIME STATUS REMOTEOWNER LINKNAME FLAGS OID$ SPARE1 SPARE2 SPARE3 SPARE4 SPARE5 SPARE6
------ -------- ---------- ---- ---------- ------- ----- ------------------- ------------------- ------------------- ---------- ----------- -------- ----- ---- ------ ------ ------ ------ ------ ------
16416 16416 40 T 1 2 2009-10-09 08:18:59 2009-10-09 08:18:59 2009-10-09 08:18:59 1 0 6 1
obj$檢視對應的插入語句如下:
Insert into SYS.OBJ$
(OBJ#, DATAOBJ#, OWNER#, NAME, NAMESPACE,
SUBNAME, TYPE#, CTIME, MTIME, STIME,
STATUS, REMOTEOWNER, LINKNAME, FLAGS, OID$,
SPARE1, SPARE2, SPARE3, SPARE4, SPARE5,
SPARE6)
Values
(16416, 16416, 40, 'T', 1,
NULL, 2, TO_DATE('10/09/2009 08:18:59', 'MM/DD/YYYY HH24:MI:SS'), TO_DATE('10/09/2009 08:18:59', 'MM/DD/YYYY HH24:MI:SS'), TO_DATE('10/09/2009 08:18:59', 'MM/DD/YYYY HH24:MI:SS'),
1, NULL, NULL, 0, NULL,
6, 1, NULL, NULL, NULL,
NULL);
3)檢視tab$檢視(為清晰的顯示,SQL*Plus下要做精心的格式化)
根據上面得到的OBJ#得到tab$檢視中關於表t的資訊
sys@ora10g> col flags clear
sys@ora10g> col flags for 99999999999
sys@ora10g> col SPARE6 clear
sys@ora10g> col AUDIT$ for a38
sys@ora10g> col SPARE1 clear
sys@ora10g> col SPARE1 for 999
sys@ora10g> col PROPERTY clear
sys@ora10g> select * from tab$ where obj# = 16416;
OBJ# DATAOBJ# TS# FILE# BLOCK# BOBJ# TAB# COLS CLUCOLS PCTFREE$ PCTUSED$ INITRANS MAXTRANS FLAGS AUDIT$ ROWCNT BLKCNT EMPCNT AVGSPC CHNCNT AVGRLN AVGSPC_FLB FLBCNT ANALYZETIME SAMPLESIZE DEGREE INSTANCES INTCOLS KERNELCOLS PROPERTY TRIGFLAG SPARE1 SPARE2 SPARE3 SPARE4 SPARE5 SPARE6
------ -------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ------------ -------------------------------------- ------ ------ ------ ------ ------ ------ ---------- ------ ------------------- ---------- ------ --------- ------- ---------- ---------- -------- ------ ------ ------ ------ ------ -------------------
16416 16416 5 5 11 2 10 40 1 255 1073741825 -------------------------------------- 2 2 536870912 0 736 2009-10-09 08:18:59
tab$檢視對應的插入語句如下:
Insert into SYS.TAB$
(OBJ#, DATAOBJ#, TS#, FILE#, BLOCK#,
BOBJ#, TAB#, COLS, CLUCOLS, PCTFREE$,
PCTUSED$, INITRANS, MAXTRANS, FLAGS, AUDIT$,
ROWCNT, BLKCNT, EMPCNT, AVGSPC, CHNCNT,
AVGRLN, AVGSPC_FLB, FLBCNT, ANALYZETIME, SAMPLESIZE,
DEGREE, INSTANCES, INTCOLS, KERNELCOLS, PROPERTY,
TRIGFLAG, SPARE1, SPARE2, SPARE3, SPARE4,
SPARE5, SPARE6)
Values
(16416, 16416, 5, 5, 11,
NULL, NULL, 2, NULL, 10,
40, 1, 255, 1073741825, '--------------------------------------',
NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
NULL, NULL, 2, 2, 536870912,
0, 736, NULL, NULL, NULL,
NULL, TO_DATE('10/09/2009 08:18:59', 'MM/DD/YYYY HH24:MI:SS'));
4)檢視col$檢視(為清晰的顯示,SQL*Plus下要做精心的格式化)
sys@ora10g> col DEFLENGTH for 9
sys@ora10g> set long 10
sys@ora10g> select * from col$ where obj# = 16416;
OBJ# COL# SEGCOL# SEGCOLLENGTH OFFSET NAME TYPE# LENGTH FIXEDSTORAGE PRECISION# SCALE NULL$ DEFLENGTH DEFAULT$ INTCOL# PROPERTY CHARSETID CHARSETFORM. SPARE1 SPARE2 SPARE3 SPARE4 SPARE5 SPARE6
------ ---------- ---------- ------------ ---------- ---- ----- ---------- ------------ ---------- ---------- ---------- --------- ---------- ---------- ---------- ---------- ----------- ------ ------ ------ ------ ------ -------------------
16416 1 1 22 0 X 2 22 0 0 1 0 0 0 0 0 0
16416 2 2 22 0 Y 2 22 0 0 2 0 0 0 0 0 0
col$檢視對應的插入語句如下:
Insert into SYS.COL$
(OBJ#, COL#, SEGCOL#, SEGCOLLENGTH, OFFSET,
NAME, TYPE#, LENGTH, FIXEDSTORAGE, PRECISION#,
SCALE, NULL$, DEFLENGTH, DEFAULT$, INTCOL#,
PROPERTY, CHARSETID, CHARSETFORM, SPARE1, SPARE2,
SPARE3, SPARE4, SPARE5, SPARE6)
Values
(16416, 1, 1, 22, 0,
'X', 2, 22, 0, NULL,
NULL, 0, NULL, NULL, 1,
0, 0, 0, 0, 0,
0, NULL, NULL, NULL);
Insert into SYS.COL$
(OBJ#, COL#, SEGCOL#, SEGCOLLENGTH, OFFSET,
NAME, TYPE#, LENGTH, FIXEDSTORAGE, PRECISION#,
SCALE, NULL$, DEFLENGTH, DEFAULT$, INTCOL#,
PROPERTY, CHARSETID, CHARSETFORM, SPARE1, SPARE2,
SPARE3, SPARE4, SPARE5, SPARE6)
Values
(16416, 2, 2, 22, 0,
'Y', 2, 22, 0, NULL,
NULL, 0, NULL, NULL, 2,
0, 0, 0, 0, 0,
0, NULL, NULL, NULL);
4.使用“set unused”語句將x列修改為不可用(背後的故事即將展現在我們的面前)
1)刪除x列
sys@ora10g> alter table sec.t set unused column x cascade constraints;
Table altered.
2)變化一:表結構的變化
前:
sec@ora10g> desc t;
Name Null? Type
---------- -------- ------------
X NUMBER
Y NUMBER
後:
sec@ora10g> desc t;
Name Null? Type
---------- -------- ------------
Y NUMBER
比較結果:顯然,x列不見了。
2)變化二:從dba_tab_cols檢視中觀察一下修改前與修改後的區別
前:
sys@ora10g> select table_name,column_name,hidden_column from dba_tab_cols where table_name='T';
TABLE_NAME COLUMN_NAME HID
------------------------------ ------------------------------ ---
T X NO
T Y NO
後:
sys@ora10g> select table_name,column_name,hidden_column from dba_tab_cols where table_name='T';
TABLE_NAME COLUMN_NAME HID
------------------------------ ------------------------------ ---
T Y NO
T SYS_C00001_09100910:19:16$ YES
比較結果:顯然,x列被系統自動標識為隱藏狀態(注意,這裡只是標註為隱藏,並沒有真正的刪除,否則就沒有這個高階的恢復方式啦)。
3)變化三:比較一下dba_objects檢視中的變化
前:
sys@ora10g> select * from dba_objects where object_name = 'T' and wner = 'SEC';
OWNER OBJECT_NAME SUB OBJECT_ID DATA_OBJECT_ID OBJECT_TYPE CREATED LAST_DDL_TIME TIMESTAMP STATUS T G S
----- ----------- --- ---------- -------------- ----------- ------------------- ------------------- ------------------- ------- - - -
SEC T 16416 16416 TABLE 2009-10-09 08:18:59 2009-10-09 08:18:59 2009-10-09:08:18:59 VALID N N N
後:
sys@ora10g> select * from dba_objects where object_name = 'T' and wner = 'SEC';
OWNER OBJECT_NAME SUB OBJECT_ID DATA_OBJECT_ID OBJECT_TYPE CREATED LAST_DDL_TIME TIMESTAMP STATUS T G S
----- ----------- --- ---------- -------------- ----------- ------------------- ------------------- ------------------- ------- - - -
SEC T 16416 16416 TABLE 2009-10-09 08:18:59 2009-10-09 10:19:16 2009-10-09:10:19:16 VALID N N N
比較結果:較顯然,觀察後,發現只有LAST_DDL_TIME和TIMESTAMP欄位發生了變化,更新了一下最後DDL的時間。
4)變化四:比較一下obj$檢視中的變化
前:
sys@ora10g> select * from obj$ where name = 'T';
OBJ# DATAOBJ# OWNER# NAME NAMESPACE SUBNAME TYPE# CTIME MTIME STIME STATUS REMOTEOWNER LINKNAME FLAGS OID$ SPARE1 SPARE2 SPARE3 SPARE4 SPARE5 SPARE6
------ -------- ---------- ---- ---------- ------- ----- ------------------- ------------------- ------------------- ---------- ----------- -------- ----- ---- ------ ------ ------ ------ ------ ------
16416 16416 40 T 1 2 2009-10-09 08:18:59 2009-10-09 08:18:59 2009-10-09 08:18:59 1 0 6 1
後:
sys@ora10g> select * from obj$ where name = 'T';
OBJ# DATAOBJ# OWNER# NAME NAMESPACE SUBNAME TYPE# CTIME MTIME STIME STATUS REMOTEOWNER LINKNAME FLAGS OID$ SPARE1 SPARE2 SPARE3 SPARE4 SPARE5 SPARE6
------ -------- ---------- ---- ---------- ------- ----- ------------------- ------------------- ------------------- ---------- ----------- -------- ----- ---- ------ ------ ------ ------ ------ ------
16416 16416 40 T 1 2 2009-10-09 08:18:59 2009-10-09 10:19:16 2009-10-09 10:19:16 1 0 6 2
比較結果:MTIME、STIME和SPARE2欄位發生變化,前兩個與結構修改有關,最後一個欄位由原來的“1”修改成了現在的“2”。
5)變化五:比較一下tab$檢視中的變化
前:
sys@ora10g> select * from tab$ where obj# = 16416;
OBJ# DATAOBJ# TS# FILE# BLOCK# BOBJ# TAB# COLS CLUCOLS PCTFREE$ PCTUSED$ INITRANS MAXTRANS FLAGS AUDIT$ ROWCNT BLKCNT EMPCNT AVGSPC CHNCNT AVGRLN AVGSPC_FLB FLBCNT ANALYZETIME SAMPLESIZE DEGREE INSTANCES INTCOLS KERNELCOLS PROPERTY TRIGFLAG SPARE1 SPARE2 SPARE3 SPARE4 SPARE5 SPARE6
------ -------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ------------ -------------------------------------- ------ ------ ------ ------ ------ ------ ---------- ------ ------------------- ---------- ------ --------- ------- ---------- ---------- -------- ------ ------ ------ ------ ------ -------------------
16416 16416 5 5 11 2 10 40 1 255 1073741825 -------------------------------------- 2 2 536870912 0 736 2009-10-09 08:18:59
後:
sys@ora10g> select * from tab$ where obj# = 16416;
OBJ# DATAOBJ# TS# FILE# BLOCK# BOBJ# TAB# COLS CLUCOLS PCTFREE$ PCTUSED$ INITRANS MAXTRANS FLAGS AUDIT$ ROWCNT BLKCNT EMPCNT AVGSPC CHNCNT AVGRLN AVGSPC_FLB FLBCNT ANALYZETIME SAMPLESIZE DEGREE INSTANCES INTCOLS KERNELCOLS PROPERTY TRIGFLAG SPARE1 SPARE2 SPARE3 SPARE4 SPARE5 SPARE6
------ -------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ------------ -------------------------------------- ------ ------ ------ ------ ------ ------ ---------- ------ ------------------- ---------- ------ --------- ------- ---------- ---------- -------- ------ ------ ------ ------ ------ -------------------
16416 16416 5 5 11 1 10 40 1 255 1073741825 -------------------------------------- 2 2 537395200 0 736 2009-10-09 10:19:16
比較結果:COLS、PROPERTY、SPARE6兩個欄位內容發生變化。重點關注COLS和PROPERTY列的變化,COLS列由原來的“2”變為了現在的“1”,因為原來表中包含2列x和y,修改後僅剩1列y;PROPERTY列用原來的“536870912”變為現在的“537395200”。
6)變化六:比較一下col$檢視中的變化
前:
sys@ora10g> col name for a26
sys@ora10g> select * from col$ where obj# = 16416;
OBJ# COL# SEGCOL# SEGCOLLENGTH OFFSET NAME TYPE# LENGTH FIXEDSTORAGE PRECISION# SCALE NULL$ DEFLENGTH DEFAULT$ INTCOL# PROPERTY CHARSETID CHARSETFORM. SPARE1 SPARE2 SPARE3 SPARE4 SPARE5 SPARE6
------ ---------- ---------- ------------ ---------- -------------------------- ----- ---------- ------------ ---------- ---------- ---------- --------- ---------- ---------- ---------- ---------- ----------- ------ ------ ------ ------ ------ -------------------
16416 1 1 22 0 X 2 22 0 0 1 0 0 0 0 0 0
16416 2 2 22 0 Y 2 22 0 0 2 0 0 0 0 0 0
後:
sys@ora10g> select * from col$ where obj# = 16416;
OBJ# COL# SEGCOL# SEGCOLLENGTH OFFSET NAME TYPE# LENGTH FIXEDSTORAGE PRECISION# SCALE NULL$ DEFLENGTH DEFAULT$ INTCOL# PROPERTY CHARSETID CHARSETFORM. SPARE1 SPARE2 SPARE3 SPARE4 SPARE5 SPARE6
------ ---------- ---------- ------------ ---------- -------------------------- ----- ---------- ------------ ---------- ---------- ---------- --------- ---------- ---------- ---------- ---------- ----------- ------ ------ ------ ------ ------ -------------------
16416 0 1 22 0 SYS_C00001_09100910:19:16$ 2 22 0 0 1 32800 0 0 0 0 0
16416 1 2 22 0 Y 2 22 0 0 2 0 0 0 0 0 0
比較結果:COL#、NAME、PROPERTY三列發生明顯變化。此三列均需重點關注。恢復時需要調整。
5.隆重推出使用“基表修改法”對被刪除的欄位進行恢復,請不要眨眼
重點修改的基表只有兩個:tab$和col$
1)恢復前檢視一下表中資料
sec@ora10g> select * from t;
Y
----------
1
2
3
2)恢復基表tab$的內容
(1)將cols欄位修改為表原有的欄位數,這裡是2行
sys@ora10g> update tab$ set cols=2 where obj#=16416;
1 row updated.
(2)經試驗證明,這一步驟可以不進行操作,修改亦無妨
update tab$ set PROPERTY=536870912 where obj#=16416;
3)恢復基表col$的內容
(1)將COL#欄位更新後保持與INTCOL#欄位內容相同
sys@ora10g> update col$ set COL#=INTCOL# where OBJ#=16416;
2 rows updated.
(2)恢復name欄位為原有面目
sys@ora10g> update col$ set name='X' where obj#=16416 and SEGCOL#=1;
1 row updated.
(3)將PROPERTY欄位統統的設定為“0”
sys@ora10g> update col$ set PROPERTY=0 where obj#=16416;
2 rows updated.
sys@ora10g> commit;
Commit complete.
4)恢復完成了,我們來Check一下恢復的效果,看到下面的內容是不是有一種崩潰的感覺,彷彿自己的一切付出都蕩然無存!不要著急,不要著急,休息一下,經繼續看我分解之。
sys@ora10g> select * from sec.t;
Y
----------
1
2
3
5)之所以上面沒有看到被恢復的x欄位內容,是因為我們沒有完成一個既簡單又不可或缺的步驟,那就是:重啟資料庫!!
重中之重:重新啟動資料庫。(為了恢復這個“小”錯誤,需要重啟資料庫,代價還是很大的!)
sys@ora10g> startup force;
ORACLE instance started.
Total System Global Area 2147483648 bytes
Fixed Size 2074152 bytes
Variable Size 486541784 bytes
Database Buffers 1644167168 bytes
Redo Buffers 14700544 bytes
Database mounted.
Database opened.
sys@ora10g> conn sec/sec
Connected.
sec@ora10g>
sec@ora10g> select * from t;
X Y
---------- ----------
1 1
2 2
3 3
6)OK,到此,整個“分解麻雀”的過程完成了,目的達到,能收工了麼?如果是在嚴峻的生產環境上遇到的這個問題,也許您還需要馬上使用其他的手段備份一下這個表中的資料,以防不測。
7)還有一種“簡單粗暴的恢復方式”,請參見《【實戰】使用“基表修改法”恢復被“set unused”方式誤刪除的列(續)》http://space.itpub.net/519536/viewspace-616175
6.重要小結
上面介紹的是一種特殊的恢復方法,是在沒有任何備份的情況下使用的極端恢復手段,對細節不瞭解的朋友要小心使用。
這個恢復案例對DBA的教訓或警告是什麼:
教訓1:為什麼會出現上面的情況,也許某些朋友對“set unused”的原理不是很熟悉,誤用了這個命令。因此如果您是一名維護DBA,在運算元據庫時,尤其是在維護生產資料庫時,一定要謹小慎微,要頭腦清醒到知道每一個“Enter”鍵背後的酸甜苦辣,否則您將極有可能因一次誤操作玩火自焚,消失在茫茫的DBA梯隊之中!!
教訓2:“備份無比崇高”,如果您有一個可用的備份,恢復這個錯誤的手段就多,給自己留一個後路,不要對自己過於放縱和隨意!!
教訓3:在做任何操作之前,要做充分的測試,不允許在生產資料庫上使用未經測試過的命令,即使這個命令表面上看上去是那麼的自然,很多DBA也許就是因為這些“自然”現象消失了!!
教訓4:慢慢補充吧,值得思考的內容很多。
請牢記:DBA是一種非常危險的動物!!珍愛DBA生命,遠離資料庫故障:)
-- The End --
透過這個文章,我來給大家深入的演示一下這個極端的恢復過程,供參考。
文中為了展示全貌,有一些不可迴避的換行,影響了顯示效果,如果您有深入研究的興趣,可以將這篇文章複製到Ultraedit中並使用“Ctrl+W”調整折行模式進行研究比較。
1.建立實驗用測試表t,並初始化資料
sec@ora10g> create table t (x number, y number);
sec@ora10g> insert into t values (1,1);
sec@ora10g> insert into t values (2,2);
sec@ora10g> insert into t values (3,3);
sec@ora10g> commit;
2.檢視錶結構和測試資料
sec@ora10g> desc t;
Name Null? Type
---------- -------- ------------
X NUMBER
Y NUMBER
sec@ora10g> select * from t;
X Y
---------- ----------
1 1
2 2
3 3
3.檢視四個檢視中關於t表的定義資訊
1)檢視dba_objects檢視(為清晰的顯示,SQL*Plus下要做精心的格式化)
sys@ora10g> col OWNER for a5
sys@ora10g> col OBJECT_NAME for a11
sys@ora10g> col SUBOBJECT_NAME for a3
sys@ora10g> col OBJECT_TYPE for a11
sys@ora10g> select * from dba_objects where object_name = 'T' and wner = 'SEC';
OWNER OBJECT_NAME SUB OBJECT_ID DATA_OBJECT_ID OBJECT_TYPE CREATED LAST_DDL_TIME TIMESTAMP STATUS T G S
----- ----------- --- ---------- -------------- ----------- ------------------- ------------------- ------------------- ------- - - -
SEC T 16416 16416 TABLE 2009-10-09 08:18:59 2009-10-09 08:18:59 2009-10-09:08:18:59 VALID N N N
2)檢視obj$檢視(為清晰的顯示,SQL*Plus下要做精心的格式化)
sys@ora10g> set lines 2000
sys@ora10g> col OBJ# for 99999
sys@ora10g> col DATAOBJ# for 99999
sys@ora10g> col name for a4
sys@ora10g> col SUBNAME for a7
sys@ora10g> col TYPE# for 99
sys@ora10g> col REMOTEOWNER for a11
sys@ora10g> col LINKNAME for a8
sys@ora10g> col FLAGS for 99
sys@ora10g> col OID$ for a4
sys@ora10g> col SPARE1 for 99
sys@ora10g> col SPARE2 for 99
sys@ora10g> col SPARE3 for 999
sys@ora10g> col SPARE4 for a6
sys@ora10g> col SPARE5 for a6
sys@ora10g> col SPARE6 for a6
sys@ora10g> select * from obj$ where name = 'T';
OBJ# DATAOBJ# OWNER# NAME NAMESPACE SUBNAME TYPE# CTIME MTIME STIME STATUS REMOTEOWNER LINKNAME FLAGS OID$ SPARE1 SPARE2 SPARE3 SPARE4 SPARE5 SPARE6
------ -------- ---------- ---- ---------- ------- ----- ------------------- ------------------- ------------------- ---------- ----------- -------- ----- ---- ------ ------ ------ ------ ------ ------
16416 16416 40 T 1 2 2009-10-09 08:18:59 2009-10-09 08:18:59 2009-10-09 08:18:59 1 0 6 1
obj$檢視對應的插入語句如下:
Insert into SYS.OBJ$
(OBJ#, DATAOBJ#, OWNER#, NAME, NAMESPACE,
SUBNAME, TYPE#, CTIME, MTIME, STIME,
STATUS, REMOTEOWNER, LINKNAME, FLAGS, OID$,
SPARE1, SPARE2, SPARE3, SPARE4, SPARE5,
SPARE6)
Values
(16416, 16416, 40, 'T', 1,
NULL, 2, TO_DATE('10/09/2009 08:18:59', 'MM/DD/YYYY HH24:MI:SS'), TO_DATE('10/09/2009 08:18:59', 'MM/DD/YYYY HH24:MI:SS'), TO_DATE('10/09/2009 08:18:59', 'MM/DD/YYYY HH24:MI:SS'),
1, NULL, NULL, 0, NULL,
6, 1, NULL, NULL, NULL,
NULL);
3)檢視tab$檢視(為清晰的顯示,SQL*Plus下要做精心的格式化)
根據上面得到的OBJ#得到tab$檢視中關於表t的資訊
sys@ora10g> col flags clear
sys@ora10g> col flags for 99999999999
sys@ora10g> col SPARE6 clear
sys@ora10g> col AUDIT$ for a38
sys@ora10g> col SPARE1 clear
sys@ora10g> col SPARE1 for 999
sys@ora10g> col PROPERTY clear
sys@ora10g> select * from tab$ where obj# = 16416;
OBJ# DATAOBJ# TS# FILE# BLOCK# BOBJ# TAB# COLS CLUCOLS PCTFREE$ PCTUSED$ INITRANS MAXTRANS FLAGS AUDIT$ ROWCNT BLKCNT EMPCNT AVGSPC CHNCNT AVGRLN AVGSPC_FLB FLBCNT ANALYZETIME SAMPLESIZE DEGREE INSTANCES INTCOLS KERNELCOLS PROPERTY TRIGFLAG SPARE1 SPARE2 SPARE3 SPARE4 SPARE5 SPARE6
------ -------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ------------ -------------------------------------- ------ ------ ------ ------ ------ ------ ---------- ------ ------------------- ---------- ------ --------- ------- ---------- ---------- -------- ------ ------ ------ ------ ------ -------------------
16416 16416 5 5 11 2 10 40 1 255 1073741825 -------------------------------------- 2 2 536870912 0 736 2009-10-09 08:18:59
tab$檢視對應的插入語句如下:
Insert into SYS.TAB$
(OBJ#, DATAOBJ#, TS#, FILE#, BLOCK#,
BOBJ#, TAB#, COLS, CLUCOLS, PCTFREE$,
PCTUSED$, INITRANS, MAXTRANS, FLAGS, AUDIT$,
ROWCNT, BLKCNT, EMPCNT, AVGSPC, CHNCNT,
AVGRLN, AVGSPC_FLB, FLBCNT, ANALYZETIME, SAMPLESIZE,
DEGREE, INSTANCES, INTCOLS, KERNELCOLS, PROPERTY,
TRIGFLAG, SPARE1, SPARE2, SPARE3, SPARE4,
SPARE5, SPARE6)
Values
(16416, 16416, 5, 5, 11,
NULL, NULL, 2, NULL, 10,
40, 1, 255, 1073741825, '--------------------------------------',
NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
NULL, NULL, 2, 2, 536870912,
0, 736, NULL, NULL, NULL,
NULL, TO_DATE('10/09/2009 08:18:59', 'MM/DD/YYYY HH24:MI:SS'));
4)檢視col$檢視(為清晰的顯示,SQL*Plus下要做精心的格式化)
sys@ora10g> col DEFLENGTH for 9
sys@ora10g> set long 10
sys@ora10g> select * from col$ where obj# = 16416;
OBJ# COL# SEGCOL# SEGCOLLENGTH OFFSET NAME TYPE# LENGTH FIXEDSTORAGE PRECISION# SCALE NULL$ DEFLENGTH DEFAULT$ INTCOL# PROPERTY CHARSETID CHARSETFORM. SPARE1 SPARE2 SPARE3 SPARE4 SPARE5 SPARE6
------ ---------- ---------- ------------ ---------- ---- ----- ---------- ------------ ---------- ---------- ---------- --------- ---------- ---------- ---------- ---------- ----------- ------ ------ ------ ------ ------ -------------------
16416 1 1 22 0 X 2 22 0 0 1 0 0 0 0 0 0
16416 2 2 22 0 Y 2 22 0 0 2 0 0 0 0 0 0
col$檢視對應的插入語句如下:
Insert into SYS.COL$
(OBJ#, COL#, SEGCOL#, SEGCOLLENGTH, OFFSET,
NAME, TYPE#, LENGTH, FIXEDSTORAGE, PRECISION#,
SCALE, NULL$, DEFLENGTH, DEFAULT$, INTCOL#,
PROPERTY, CHARSETID, CHARSETFORM, SPARE1, SPARE2,
SPARE3, SPARE4, SPARE5, SPARE6)
Values
(16416, 1, 1, 22, 0,
'X', 2, 22, 0, NULL,
NULL, 0, NULL, NULL, 1,
0, 0, 0, 0, 0,
0, NULL, NULL, NULL);
Insert into SYS.COL$
(OBJ#, COL#, SEGCOL#, SEGCOLLENGTH, OFFSET,
NAME, TYPE#, LENGTH, FIXEDSTORAGE, PRECISION#,
SCALE, NULL$, DEFLENGTH, DEFAULT$, INTCOL#,
PROPERTY, CHARSETID, CHARSETFORM, SPARE1, SPARE2,
SPARE3, SPARE4, SPARE5, SPARE6)
Values
(16416, 2, 2, 22, 0,
'Y', 2, 22, 0, NULL,
NULL, 0, NULL, NULL, 2,
0, 0, 0, 0, 0,
0, NULL, NULL, NULL);
4.使用“set unused”語句將x列修改為不可用(背後的故事即將展現在我們的面前)
1)刪除x列
sys@ora10g> alter table sec.t set unused column x cascade constraints;
Table altered.
2)變化一:表結構的變化
前:
sec@ora10g> desc t;
Name Null? Type
---------- -------- ------------
X NUMBER
Y NUMBER
後:
sec@ora10g> desc t;
Name Null? Type
---------- -------- ------------
Y NUMBER
比較結果:顯然,x列不見了。
2)變化二:從dba_tab_cols檢視中觀察一下修改前與修改後的區別
前:
sys@ora10g> select table_name,column_name,hidden_column from dba_tab_cols where table_name='T';
TABLE_NAME COLUMN_NAME HID
------------------------------ ------------------------------ ---
T X NO
T Y NO
後:
sys@ora10g> select table_name,column_name,hidden_column from dba_tab_cols where table_name='T';
TABLE_NAME COLUMN_NAME HID
------------------------------ ------------------------------ ---
T Y NO
T SYS_C00001_09100910:19:16$ YES
比較結果:顯然,x列被系統自動標識為隱藏狀態(注意,這裡只是標註為隱藏,並沒有真正的刪除,否則就沒有這個高階的恢復方式啦)。
3)變化三:比較一下dba_objects檢視中的變化
前:
sys@ora10g> select * from dba_objects where object_name = 'T' and wner = 'SEC';
OWNER OBJECT_NAME SUB OBJECT_ID DATA_OBJECT_ID OBJECT_TYPE CREATED LAST_DDL_TIME TIMESTAMP STATUS T G S
----- ----------- --- ---------- -------------- ----------- ------------------- ------------------- ------------------- ------- - - -
SEC T 16416 16416 TABLE 2009-10-09 08:18:59 2009-10-09 08:18:59 2009-10-09:08:18:59 VALID N N N
後:
sys@ora10g> select * from dba_objects where object_name = 'T' and wner = 'SEC';
OWNER OBJECT_NAME SUB OBJECT_ID DATA_OBJECT_ID OBJECT_TYPE CREATED LAST_DDL_TIME TIMESTAMP STATUS T G S
----- ----------- --- ---------- -------------- ----------- ------------------- ------------------- ------------------- ------- - - -
SEC T 16416 16416 TABLE 2009-10-09 08:18:59 2009-10-09 10:19:16 2009-10-09:10:19:16 VALID N N N
比較結果:較顯然,觀察後,發現只有LAST_DDL_TIME和TIMESTAMP欄位發生了變化,更新了一下最後DDL的時間。
4)變化四:比較一下obj$檢視中的變化
前:
sys@ora10g> select * from obj$ where name = 'T';
OBJ# DATAOBJ# OWNER# NAME NAMESPACE SUBNAME TYPE# CTIME MTIME STIME STATUS REMOTEOWNER LINKNAME FLAGS OID$ SPARE1 SPARE2 SPARE3 SPARE4 SPARE5 SPARE6
------ -------- ---------- ---- ---------- ------- ----- ------------------- ------------------- ------------------- ---------- ----------- -------- ----- ---- ------ ------ ------ ------ ------ ------
16416 16416 40 T 1 2 2009-10-09 08:18:59 2009-10-09 08:18:59 2009-10-09 08:18:59 1 0 6 1
後:
sys@ora10g> select * from obj$ where name = 'T';
OBJ# DATAOBJ# OWNER# NAME NAMESPACE SUBNAME TYPE# CTIME MTIME STIME STATUS REMOTEOWNER LINKNAME FLAGS OID$ SPARE1 SPARE2 SPARE3 SPARE4 SPARE5 SPARE6
------ -------- ---------- ---- ---------- ------- ----- ------------------- ------------------- ------------------- ---------- ----------- -------- ----- ---- ------ ------ ------ ------ ------ ------
16416 16416 40 T 1 2 2009-10-09 08:18:59 2009-10-09 10:19:16 2009-10-09 10:19:16 1 0 6 2
比較結果:MTIME、STIME和SPARE2欄位發生變化,前兩個與結構修改有關,最後一個欄位由原來的“1”修改成了現在的“2”。
5)變化五:比較一下tab$檢視中的變化
前:
sys@ora10g> select * from tab$ where obj# = 16416;
OBJ# DATAOBJ# TS# FILE# BLOCK# BOBJ# TAB# COLS CLUCOLS PCTFREE$ PCTUSED$ INITRANS MAXTRANS FLAGS AUDIT$ ROWCNT BLKCNT EMPCNT AVGSPC CHNCNT AVGRLN AVGSPC_FLB FLBCNT ANALYZETIME SAMPLESIZE DEGREE INSTANCES INTCOLS KERNELCOLS PROPERTY TRIGFLAG SPARE1 SPARE2 SPARE3 SPARE4 SPARE5 SPARE6
------ -------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ------------ -------------------------------------- ------ ------ ------ ------ ------ ------ ---------- ------ ------------------- ---------- ------ --------- ------- ---------- ---------- -------- ------ ------ ------ ------ ------ -------------------
16416 16416 5 5 11 2 10 40 1 255 1073741825 -------------------------------------- 2 2 536870912 0 736 2009-10-09 08:18:59
後:
sys@ora10g> select * from tab$ where obj# = 16416;
OBJ# DATAOBJ# TS# FILE# BLOCK# BOBJ# TAB# COLS CLUCOLS PCTFREE$ PCTUSED$ INITRANS MAXTRANS FLAGS AUDIT$ ROWCNT BLKCNT EMPCNT AVGSPC CHNCNT AVGRLN AVGSPC_FLB FLBCNT ANALYZETIME SAMPLESIZE DEGREE INSTANCES INTCOLS KERNELCOLS PROPERTY TRIGFLAG SPARE1 SPARE2 SPARE3 SPARE4 SPARE5 SPARE6
------ -------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ------------ -------------------------------------- ------ ------ ------ ------ ------ ------ ---------- ------ ------------------- ---------- ------ --------- ------- ---------- ---------- -------- ------ ------ ------ ------ ------ -------------------
16416 16416 5 5 11 1 10 40 1 255 1073741825 -------------------------------------- 2 2 537395200 0 736 2009-10-09 10:19:16
比較結果:COLS、PROPERTY、SPARE6兩個欄位內容發生變化。重點關注COLS和PROPERTY列的變化,COLS列由原來的“2”變為了現在的“1”,因為原來表中包含2列x和y,修改後僅剩1列y;PROPERTY列用原來的“536870912”變為現在的“537395200”。
6)變化六:比較一下col$檢視中的變化
前:
sys@ora10g> col name for a26
sys@ora10g> select * from col$ where obj# = 16416;
OBJ# COL# SEGCOL# SEGCOLLENGTH OFFSET NAME TYPE# LENGTH FIXEDSTORAGE PRECISION# SCALE NULL$ DEFLENGTH DEFAULT$ INTCOL# PROPERTY CHARSETID CHARSETFORM. SPARE1 SPARE2 SPARE3 SPARE4 SPARE5 SPARE6
------ ---------- ---------- ------------ ---------- -------------------------- ----- ---------- ------------ ---------- ---------- ---------- --------- ---------- ---------- ---------- ---------- ----------- ------ ------ ------ ------ ------ -------------------
16416 1 1 22 0 X 2 22 0 0 1 0 0 0 0 0 0
16416 2 2 22 0 Y 2 22 0 0 2 0 0 0 0 0 0
後:
sys@ora10g> select * from col$ where obj# = 16416;
OBJ# COL# SEGCOL# SEGCOLLENGTH OFFSET NAME TYPE# LENGTH FIXEDSTORAGE PRECISION# SCALE NULL$ DEFLENGTH DEFAULT$ INTCOL# PROPERTY CHARSETID CHARSETFORM. SPARE1 SPARE2 SPARE3 SPARE4 SPARE5 SPARE6
------ ---------- ---------- ------------ ---------- -------------------------- ----- ---------- ------------ ---------- ---------- ---------- --------- ---------- ---------- ---------- ---------- ----------- ------ ------ ------ ------ ------ -------------------
16416 0 1 22 0 SYS_C00001_09100910:19:16$ 2 22 0 0 1 32800 0 0 0 0 0
16416 1 2 22 0 Y 2 22 0 0 2 0 0 0 0 0 0
比較結果:COL#、NAME、PROPERTY三列發生明顯變化。此三列均需重點關注。恢復時需要調整。
5.隆重推出使用“基表修改法”對被刪除的欄位進行恢復,請不要眨眼
重點修改的基表只有兩個:tab$和col$
1)恢復前檢視一下表中資料
sec@ora10g> select * from t;
Y
----------
1
2
3
2)恢復基表tab$的內容
(1)將cols欄位修改為表原有的欄位數,這裡是2行
sys@ora10g> update tab$ set cols=2 where obj#=16416;
1 row updated.
(2)經試驗證明,這一步驟可以不進行操作,修改亦無妨
update tab$ set PROPERTY=536870912 where obj#=16416;
3)恢復基表col$的內容
(1)將COL#欄位更新後保持與INTCOL#欄位內容相同
sys@ora10g> update col$ set COL#=INTCOL# where OBJ#=16416;
2 rows updated.
(2)恢復name欄位為原有面目
sys@ora10g> update col$ set name='X' where obj#=16416 and SEGCOL#=1;
1 row updated.
(3)將PROPERTY欄位統統的設定為“0”
sys@ora10g> update col$ set PROPERTY=0 where obj#=16416;
2 rows updated.
sys@ora10g> commit;
Commit complete.
4)恢復完成了,我們來Check一下恢復的效果,看到下面的內容是不是有一種崩潰的感覺,彷彿自己的一切付出都蕩然無存!不要著急,不要著急,休息一下,經繼續看我分解之。
sys@ora10g> select * from sec.t;
Y
----------
1
2
3
5)之所以上面沒有看到被恢復的x欄位內容,是因為我們沒有完成一個既簡單又不可或缺的步驟,那就是:重啟資料庫!!
重中之重:重新啟動資料庫。(為了恢復這個“小”錯誤,需要重啟資料庫,代價還是很大的!)
sys@ora10g> startup force;
ORACLE instance started.
Total System Global Area 2147483648 bytes
Fixed Size 2074152 bytes
Variable Size 486541784 bytes
Database Buffers 1644167168 bytes
Redo Buffers 14700544 bytes
Database mounted.
Database opened.
sys@ora10g> conn sec/sec
Connected.
sec@ora10g>
sec@ora10g> select * from t;
X Y
---------- ----------
1 1
2 2
3 3
6)OK,到此,整個“分解麻雀”的過程完成了,目的達到,能收工了麼?如果是在嚴峻的生產環境上遇到的這個問題,也許您還需要馬上使用其他的手段備份一下這個表中的資料,以防不測。
7)還有一種“簡單粗暴的恢復方式”,請參見《【實戰】使用“基表修改法”恢復被“set unused”方式誤刪除的列(續)》http://space.itpub.net/519536/viewspace-616175
6.重要小結
上面介紹的是一種特殊的恢復方法,是在沒有任何備份的情況下使用的極端恢復手段,對細節不瞭解的朋友要小心使用。
這個恢復案例對DBA的教訓或警告是什麼:
教訓1:為什麼會出現上面的情況,也許某些朋友對“set unused”的原理不是很熟悉,誤用了這個命令。因此如果您是一名維護DBA,在運算元據庫時,尤其是在維護生產資料庫時,一定要謹小慎微,要頭腦清醒到知道每一個“Enter”鍵背後的酸甜苦辣,否則您將極有可能因一次誤操作玩火自焚,消失在茫茫的DBA梯隊之中!!
教訓2:“備份無比崇高”,如果您有一個可用的備份,恢復這個錯誤的手段就多,給自己留一個後路,不要對自己過於放縱和隨意!!
教訓3:在做任何操作之前,要做充分的測試,不允許在生產資料庫上使用未經測試過的命令,即使這個命令表面上看上去是那麼的自然,很多DBA也許就是因為這些“自然”現象消失了!!
教訓4:慢慢補充吧,值得思考的內容很多。
請牢記:DBA是一種非常危險的動物!!珍愛DBA生命,遠離資料庫故障:)
-- The End --
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/519536/viewspace-616174/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 【實戰】使用“基表修改法”恢復被“set unused”方式誤刪除的列(續)
- 表的列被set unused的機制
- DB2 恢復誤刪除的表DB2
- 【北亞資料恢復】誤刪除oracle表和誤刪除oracle表資料的資料恢復方法資料恢復Oracle
- flashback database 恢復誤刪除的表空間。Database
- 使用lsof恢復誤刪除的檔案
- 恢復 Git 被刪除的分支Git
- Git恢復被刪除的分支Git
- ZT:使用lsof恢復誤刪除的檔案
- MySQL資料庫表誤刪除恢復(一)MySql資料庫
- 通過flashback database恢復被刪除的表空間Database
- 恢復被刪除的Word選單
- 2 Day DBA-管理方案物件-執行備份和恢復-使用Oracle閃回刪除功能恢復被刪除的表物件Oracle
- 恢復被設定為Unused的欄位
- 恢復被刪除的Word選單(轉)
- oracle恢復誤刪除資料Oracle
- 被誤刪的檔案快速恢復方法
- Oracle 11g RMAN恢復-使用者誤刪除表空間Oracle
- Redo log檔案被刪除恢復
- 表資料被誤操作的恢復
- 使用閃回查詢恢復誤刪除的資料
- logminer來恢復在表DDL之前被刪除的資料
- ORACLE 11g TSPITR恢復被刪除的表空間Oracle
- 【EM】資料表誤刪除故障模擬及恢復
- Oracle恢復誤操作刪除掉的表Oracle
- 儲存過程誤刪除的恢復儲存過程
- 如何恢復被刪除的 GitLab 專案?Gitlab
- Oracle 10g 中誤刪除(drop)表的恢復處理Oracle 10g
- Oracle閃回刪除恢復誤刪資料Oracle
- lsof恢復oracle誤刪除檔案Oracle
- Linux教程-使用mc恢復被刪除檔案(轉)Linux
- EMC NAS中虛擬機器被誤刪除的資料恢復案例虛擬機資料恢復
- Oracle恢復誤刪除的資料檔案Oracle
- truncate table 誤刪除資料後的恢復
- 【伺服器資料恢復】XenServer虛擬機器被誤操作刪除的資料恢復案例伺服器資料恢復Server虛擬機
- oracle8i誤刪除臨時表空間後的恢復Oracle
- 恢復EXT3下被刪除的檔案
- 被360防毒刪除的檔案怎麼恢復防毒