总体概况
在数据库中创建DDL 触发器和DDL 表时,发现在drop 表的时候,oracle 内部会先把表给rename 后再drop 到回收站内。那这个rename 的操作有什么特殊的含义,接下来就是研究过程
创建DDL 表和DDL 触发器来跟踪drop 表的过程
我在研究通过建立ddl 表和ddl 触发器来记录数据库中ddl 的操作日志的时候发现一个有意思的事:
1. 创建DDL 表和DDL 触发器
---- 存储DDL 语句的表
create table sys.my_audit_ddl(
opertime timestamp PRIMARY KEY,
ip varchar2(20),
hostname varchar2(30),
operation varchar2(30),
object_type varchar2(30),
object_name varchar2(30),
sql_stmt clob,
db_schema varchar2(30)
);
---- 捕获DDL 语句的触发器
CREATE OR REPLACE TRIGGER sys.trg_my_audit_ddl
after ddl ON DATABASE
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
n NUMBER;
stmt clob := NULL;
sql_text ora_name_list_t;
BEGIN
n := ora_sql_txt(sql_text);
FOR i IN 1 .. n LOOP
stmt := stmt || sql_text(i);
END LOOP;
INSERT INTO sys.my_audit_ddl
(opertime, ip, hostname, operation, object_type, object_name, sql_stmt,db_schema)
VALUES
(systimestamp,
sys_context('userenv', 'ip_address'),
sys_context('userenv', 'terminal'),
ora_sysevent,
ora_dict_obj_type,
ora_dict_obj_name,
stmt,
user
);
COMMIT;
END;
/
2. 在test 用户下建一张test 表
create table test (
name varchar2(20),id number(2));
用sys 用户查询那张ddl 记录表:
SQL> select SQL_STMT,OPERTIME from sys.my_audit_ddl;
SQL_STMT OPERTIME
---------------------------------- ------------------------------
create table test ( 04-AUG-17 01.46.50.762982 PM
name varchar2(20),id number(2))
可以看到创建的记录被记录下来。
用test 用户删除这张test 表(不加purge ):
drop table test;
3. 发现ddl 记录的过程中,多了一行
SQL> select SQL_STMT,OPERTIME from sys.my_audit_ddl;
SQL_STMT OPERTIME
-------------------------------------------------------------------------- -- ------------------------------
create table test ( 04-AUG-17 01.46.50.762982 PM
name varchar2(20),id number(2))
ALTER TABLE "TEST"."TEST" RENAME TO "BIN$VegNdsxaqv7gU2UoqMD5iA==$0" 04-AUG-17 01.48.56.035327 PM
drop table test 04-AUG-17 01.48.56.149173 PM
在删除这张表进入回收站之前,会先将这张表更改名字,然后再删除这张表。
去回收站内查看:
SQL> select owner,object_name from dba_recyclebin;
OWNER OBJECT_NAME ORIGINAL_NAME
------------------------------ ------------------------------ ----------------------
TEST BIN$VegNdsxaqv7gU2UoqMD5iA ==$0 TEST
可以看到,在回收站内看到的表名,被改成BIN 开头的名字,同时原名也记录在其中。
4. 那这个object_name 有什么用呢?
我们在使用flashback table 的时候,语句一般是这样的:
flashback table test to before drop;
这个时候,回收站内的test 表,会被还原到原用户下。
但如果如果一个用户,连续两次删除了一张同名表呢?
还原的时候指定这两张同名表的时候,回收站会默认还原距离当前时间最近被删除的一张表:
SQL> select object_name,original_name,droptime,dropscn from user_recyclebin;
OBJECT_NAME ORIGINAL_NAME DROPTIME DROPSCN
------------------------------ -------------------------------- ------------------- ----------
BIN$VehKONsSsmrgU2UoqMAAqA==$0 TEST01 2017-08-04:14:12:00 1171519
BIN$Vek/0SbO3ODgU2UoqMBrzQ==$0 TEST01 2017-08-04:15:22:30 1175274
SQL>flashback table test01 to before drop;
SQL> select object_name,original_name,droptime,dropscn from user_recyclebin;
OBJECT_NAME ORIGINAL_NAME DROPTIME DROPSCN
------------------------------ -------------------------------- ------------------- ----------
BIN$VehKONsSsmrgU2UoqMAAqA==$0 TEST01 2017-08-04:14:12:00 1171519
5. 那我们如果想还原的不是这张距离时间最近的表呢?
那么这个时候就需要用到object_name 了。
通过指定object_name ,我们可以还原任意一张表:
SQL> select object_name,original_name,droptime,dropscn from user_recyclebin;
OBJECT_NAME ORIGINAL_NAME DROPTIME DROPSCN
------------------------------ -------------------------------- ------------------- ----------
BIN$VehKONsSsmrgU2UoqMAAqA==$0 TEST01 2017-08-04:14:12:00 1171519
BIN$Vek/0SbO3ODgU2UoqMBrzQ==$0 TEST01 2017-08-04:15:22:30 1175274
SQL>flashback table “ BIN$VehKONsSsmrgU2UoqMAAqA==$0” to before drop;
这就是在drop 的时候,为什么oracle 会先把表给rename 成一个特殊的名字的原因之一。