用户错误是指用户的误操作,例如误删除表、误截断定表、错误的DML操作等。为了避免用户误操作,必须要培训用户,使他们知道DB可用性和完整性的含义,并且告诉他们什么操作可以做,什么操作不可以做。
1,DROP TABLE误操作
当执行了DROP TABLE操作之后,会删除表结构及其数据。在Oracle 10g之前,如果误删除了表,那么可以使用以下几种解决方法:
- 使用IMPORT工具导入表结构及其数据,但这种方法可能会丢失部份数据。假定用户在2008年8月21日09:00时导出了EMP表的结构极其数据,在2008年8月21日11:00时误删除了EMP表,此时可以用09:00使用EXP工具导出的数据,但是会丢失09:00时之后的2小时数据。
- 基于时间点的DB不完全恢复(DBPITR),这种方法可以确保不会丢失EMP表的数据,但可能会丢失其他表空间事务操作的数据。注意,DBPITR只适用于ARCHIVELOG模式。
- 使用基于时间点的表空间不完全恢复(TSPITR),这种方法不仅可以确保不会丢失EMP表的任何数据,还可以确保不会丢失其他表空间事务操作的数据。注意,TSPITR只适用于ARCHIVELOG模式。
从Oracle Database 10g 开始,通过使用FLASHBACK TABLE 语句不仅可以快速恢复表,而且也不会影响任何其他表空间和其他表。在Oracle database 10g 中,当执行DROP TABLE 操作时,表结构和数据不会立即清除,而是被放在DB 回收站中(Recyclebin) 中。如果表段所在表空间足够大,那么其内容可能永远不会被清除,些时通过FLASHBACK TABLE可以快速恢复表。
Example:
SQL> select count(1) from emp;
COUNT(1)
----------
14
SQL> drop table emp;
表已删除。
SQL> select count(1) from emp;
select count(1) from emp
*
第 1 行出现错误:
ORA-00942: 表或视图不存在
SQL> flashback table emp to before drop;
闪回完成。
SQL> select count(1) from emp;
COUNT(1)
----------
14
2, TRUNCATE TABLE 操作
当执行了TRUNCATE TABLE 操作之后,会删除表的所有数据,但是会保留表结构。如果执行了TRUNCATE TABLE 误操作,那么解决方法类似于DROP TABLE。具体方法如下:
- 使用IMPORT 工具导入表数据,但这种方法可能会丢失部分数据。因为表的结构已经存在,所以在使用IMP 导入表时应该指定IGNOGE=Y(忽略创建错误)选项。
- 使用基于时间点的DB不完全恢复(DBPITR),这种方法可以确保不会丢失EMP 表的任何数据,但是可以会丢失其它表空间事务操作的数据。
- 使用基于时间点的TABLESPACE 不完全恢复(TSPITR),这种方法不仅可以确保不会丢失EMP 表的DATA,还可以确保不会丢失其它表空间事务操作的数据。
3,DML 误操作
当执行了DML 误操作之后,如果事务没有被提交,那么执行ROLLBACK 语句就可以取消误操作。但如果在DML 误操作之后执行了COMMIT 操作,那么必须解决误操作所带来的影响。在Oracle Database 10g 之前,DBA 可以使用LogMiner 工具分析特定时间段的DML操作,并生成DML 源操作、反操作(INSERT反操作:DELETE,DELETE 反操作:INSERT,UPDATE 反操作:UPDATE)以及相关数据。在确定了错误的DML操作之后,只要执行相应的反操作就可以了。
从Oracle Database 10g 开始,当执行了DML 误操作之后,使用FLASHBACK TABLE 语句可以将表数据恢复到过去的时间点或者过去的SCN(System Change Number)值。注意,如果要使用该特征,那么必须激活表的行移动特征;另外FLASHBACK TABLE 所能恢复到的最早时间受限于初始化参数db_flashback_retention_target。
Example:
SQL> connect scott/tiger@orcl
已连接。
SQL> Alter Table EMP Enable Row Movement;
表已更改。
SQL> select * from emp where empno=7788;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- -------------- ---------- ---------- ----------
7788 SCOTT ANALYST 7566 19-4月 -87 3000 20
SQL> update emp set sal=sal*1.5 where empno=7788;
已更新 1 行。
SQL> commit;
提交完成。
SQL> select * from emp where empno=7788;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- -------------- ---------- ---------- ----------
7788 SCOTT ANALYST 7566 19-4月 -87 4500 20
SQL> flashback table emp to timestamp to_timestamp('2008-08-21 18:20:00', 'YYYY-MM-DD HH24:MI:SS');
闪回完成。
SQL> select * from emp where empno=7788;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- -------------- ---------- ---------- ----------
7788 SCOTT ANALYST 7566 19-4月 -87 3000 20