恢复DELETE数据的PACKAGE(介绍篇)
目的
在"不小心"对表执行了delete操作,并"不小心"提交之后,如果没有闪回、备份等常规恢复手段,那就傻眼了。
我在学习bbed的时候,有学到通过修改行标记来恢复delete的数据的手段,但这种方法存在风险,且较为复杂,于是思考是否有更简单更安全的方法。
至此,这个PACKAGE诞生了,虽然还很稚嫩。
目前该版本仅支持恢复NUMBER, VARCHAR2, CHAR, DATE, TIMESTAMP, RAW这六种数据类型。
其他数据类型将被恢复为null(如CLOB、BLOB、XMLTYPE、INTERVAL 等)。
需注意部分不支持的数据类型会导致数据读取错误(目前已知会导致错误的有LONG、LONG RAW)。
适用环境
-
目前已知适用于Oracle11g和Oracle19c,期间版本和更高版理论是支持的,但未经过测试。
-
仅支持恢复普通表,暂不支持如分区表、索引组织表等类型的表。
-
支持CDB/PDB环境
-
暂不支持RAC(不支持共享存储)
-
前提条件:
源表没有被drop
数据块未被重用或覆盖
原理简介
Oracle的数据存储于数据文件当中,而delete一个表后,被delete的数据不会立刻消失,在被复用之前仍会存储在数据文件上。
此时只需要找到目标表数据存储的位置,并将底层数据读取出来并进行对应转换,就能得到真实的数据,再将这些数据插入到一张结构一致的新表上,数据就成功恢复了。
使用演示
创建PACKAGE
sql
SQL> alter session set container=pdb1;
Session altered.
SQL> @del_recover_basic.sql
Installing DEL_RECOVER_BASIC package...
Package created.
Package body created.
Package DEL_RECOVER_BASIC installed end.
To display usage, execute: EXEC DEL_RECOVER_BASIC.usage
Disconnected from Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.28.0.0.0
准备测试表
sql
DROP TABLE test.basic_types_test PURGE;
CREATE TABLE test.basic_types_test (
id NUMBER(10) PRIMARY KEY,
num_col NUMBER(12,2),
vc_col VARCHAR2(200),
char_col CHAR(10),
date_col DATE,
ts_col TIMESTAMP(6),
raw_col RAW(200)
);
INSERT INTO test.basic_types_test VALUES (
1,
12345.67,
'Hello, World!',
'FIXED',
TO_DATE('2024-01-15 10:30:00', 'YYYY-MM-DD HH24:MI:SS'),
TIMESTAMP '2024-01-15 10:30:00.123456',
HEXTORAW('1A2B3C4D')
);
INSERT INTO test.basic_types_test VALUES (
2,
-9876.54,
RPAD('Long string test ', 190, 'X'),
'ABC ',
TO_DATE('1999-12-31 23:59:59', 'YYYY-MM-DD HH24:MI:SS'),
TIMESTAMP '1999-12-31 23:59:59.999999',
HEXTORAW('FFEEDDCCBBAA')
);
INSERT INTO test.basic_types_test VALUES (
3,
0,
'',
'',
NULL,
NULL,
NULL
);
INSERT INTO test.basic_types_test VALUES (
4,
NULL,
NULL,
NULL,
SYSDATE,
SYSTIMESTAMP,
HEXTORAW(RPAD('FF', 200, 'FF'))
);
INSERT INTO test.basic_types_test VALUES (
5,
0.01,
'A',
'1234567890',
TO_DATE('2020-02-29 12:00:00', 'YYYY-MM-DD HH24:MI:SS'),
TIMESTAMP '2020-02-29 12:00:00.000001',
HEXTORAW('01')
);
COMMIT;
set linesize 999
set pagesize 999
COLUMN vc_col FORMAT a30
COLUMN char_col FORMAT a10
COLUMN date_col FORMAT a19
COLUMN ts_col FORMAT a19
COLUMN raw_hex FORMAT a30
SQL> SELECT id,
num_col,
vc_col,
char_col,
TO_CHAR(date_col, 'YYYY-MM-DD HH24:MI:SS') AS date_col,
TO_CHAR(ts_col, 'YYYY-MM-DD HH24:MI:SS') AS ts_col,
RAWTOHEX(raw_col) AS raw_hex
FROM test.basic_types_test
ORDER BY id;
ID NUM_COL VC_COL CHAR_COL DATE_STR TS_STR RAW_HEX
------ --------- ------------------------------ ---------- ------------------- -------------------------- ------------------------------
1 12345.67 Hello, World! FIXED 2024-01-15 10:30:00 2024-01-15 10:30:00.123456 1A2B3C4D
2 -9876.54 Long string test XXXXXXXXXXXXX ABC 1999-12-31 23:59:59 1999-12-31 23:59:59.999999 FFEEDDCCBBAA
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXX
3 .00
4 2026-06-03 17:44:06 2026-06-03 17:44:06.359346 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFF
5 .01 A 1234567890 2020-02-29 12:00:00 2020-02-29 12:00:00.000001 01
模拟误删除
sql
SQL> delete from test.basic_types_test;
5 rows deleted.
SQL> commit;
Commit complete.
SQL> alter system checkpoint;
System altered.
SQL> select * from test.basic_types_test;
no rows selected
执行恢复
在执行package之前,需要有一个指向"要恢复的表所在的数据文件所在的路径"的目录,如没有,执行时会报错并提供推荐的创建语句,创建后重新执行即可。
更多详细的用法,请见下一文章操作手册篇。
sql
SQL> SET SERVEROUTPUT ON
SQL> EXEC DEL_RECOVER_BASIC.recover_deleted_table('TEST', 'BASIC_TYPES_TEST', 'TEST');
17:57:06: Source table: TEST.BASIC_TYPES_TEST, DATA_OBJ#=75104, TS=TESTDATAFILE
17:57:06: Creating recovery table: TEST.R_BASIC_TYPES_TEST
17:57:06: Recovery table created successfully: TEST.R_BASIC_TYPES_TEST
17:57:06: Processing datafile:
/u01/app/oracle/oradata/ORCL/4A74127AED179CCAE0632400A8C0B3DF/datafile/o1_mf_tes
tdata_nvhbjhnd_.dbf using directory BBED_DATA_DIR
17:57:06: Recovery completed. Total rows recovered: 5
17:57:06: Data stored in table: TEST.R_BASIC_TYPES_TEST
PL/SQL procedure successfully completed.
验证恢复结果
sql
SQL> SELECT id,
num_col,
vc_col,
char_col,
TO_CHAR(date_col, 'YYYY-MM-DD HH24:MI:SS') AS date_col,
TO_CHAR(ts_col, 'YYYY-MM-DD HH24:MI:SS') AS ts_col,
RAWTOHEX(raw_col) AS raw_hex
FROM test.r_basic_types_test
ORDER BY id;
ID NUM_COL VC_COL CHAR_COL DATE_COL TS_COL RAW_HEX
---------- ---------- ------------------------------ ---------- ------------------- ------------------- ------------------------------
1 12345.67 Hello, World! FIXED 2024-01-15 10:30:00 2024-01-15 10:30:00 1A2B3C4D
2 -9876.54 Long string test XXXXXXXXXXXXX ABC 1999-12-31 23:59:59 1999-12-31 23:59:59 FFEEDDCCBBAA
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXX
3 0
4 2026-06-03 17:44:06 2026-06-03 17:44:06 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFF
5 .01 A 1234567890 2020-02-29 12:00:00 2020-02-29 12:00:00 01
package下载链接