Oracle的学习心得和知识总结(一)|Oracle数据库闪回技术详解


注:提前言明 本文借鉴了以下博主、书籍或网站的内容,其列表如下:

1、Oracle闪回详解,点击前往
2、Oracle闪回技术详解,点击前往
3、参考书籍:《涂抹Oracle 三思笔记之一步一步学Oracle》
4、参考书籍:《Oracle Database 11g数据库管理艺术》
5、Flashback Transaction Backout,点击前往
6、关于oracle闪回数据归档的总结,点击前往
7、参考书籍:《Oracle Database 9i10g11g编程艺术深入数据库体系结构(第2版)》




文章快速说明索引

学习目标:

目的:因为接下来想在PostgreSQL上实践实现一下 闪回操作 ,但是就目前而言 PostgreSQL尚不支持此功能。德哥的git和其他PostgreSQL社区爱好者也曾分享过一些 类似的 闪回简易实现,大家有兴趣也可以去看看!本文主要记录在Oracle数据库上面的闪回功能的使用体验和基于开发者的设计思考,以期在PostgreSQL数据库上面支持此功能!


学习内容:(详见目录)

1、Oracle数据库的闪回技术


学习时间:

2020年9月16日03:36:25 - 2020年9月27日23:33:51


学习产出:

1、Oracle数据库闪回技术学习
2、CSDN 技术博客 1篇
3、PostgreSQL数据库闪回功能实现设计思考


Oracle闪回的概述

闪回概述

Flashback 即 数据库闪回操作,它是Oracle自9i版本才开始提供的一项新特性,在Oracle 10g中对功能进行了增强。在10g之前只提供了 闪回查询 的功能,进入10g之后又提供了对事务、对表的恢复,以及真正具有恢复意味的闪回数据库的功能。在Oracle11g之后这些功能日趋更加完善。闪回技术是Oracle强大数据库备份恢复机制的一部分,在数据库发生逻辑错误的时候,闪回技术能提供快速且最小损失的恢复(多数闪回功能都能在数据库联机状态下完成)。需要注意的是,闪回技术旨在快速恢复逻辑错误,对于物理损坏或是介质丢失的错误,闪回技术就回天乏术了,还是得借助于Oracle一些高级的备份恢复工具如RAMN去完成。

闪回特性的优点在于语法简单、操作方便和功能强大,其作用在于快速恢复数据和查询历史数据。在Oracle 10g中的闪回功能可以分成以下三个方面:

  • 闪回查询(Flashback Query) :通过查询UNDO段, 能够重现操作之前的数据
  • 闪回表(Flashback Table) :该特性与10g中新推出的另外一项新增特性Recycle Bin(回收站) 对应, 默认情况下表对象及其关联的索引等对象在DROP后并没有物理删除, 而是标记为删除(类似在Windows中删除文件时, 文件移向“回收站”的概念),如果你想对这类表进行恢复,只需要简单的命令即可,而且该操作只修改数据字典,不管要恢复的对象占用多大空间,恢复效率极高
  • 闪回数据库(Flashback Database) :该功能十分强大, 真正实现了不需要备份的恢复(严格地讲还是有备份, 只不过这个备份操作不由DBA做, 而是Oracle自动进行)

详细内容展开如下表所示:(基于Oracle 11g的闪回技术)

闪回技术闪回级别 场景描述功能描述对象依赖是否影响数据
Flashback DatabaseDatabase表截断、逻辑错误、其他多表意外事件将整个数据库倒退到一个特定的时刻闪回日志、undo logYES
Flashback TableTable更新、删除、插入记录将表返回到过去的一个状态还原数据、undo logYES
Flashback DROPDrop删除表撤销DROP TABLE命令并恢复被删除的表recyclebinYES
Flashback QUERYQuery当前数据和历史数据对比检索过去某一时刻(或时间间隔)的数据还原数据、undo logNO
Flashback Version QueryVersion Query比较行版本同上同上NO
Flashback Transaction QueryTransaction Query比较事务同上同上NO
Flashback Transaction BackoutTransaction Backout撤销事务在Database Control中单击一下, 撤销一个事务以及它依赖的所有事务undo logYES
Flashback Data ArchiveArchiveDDL、DML存储对一个表所做更改的历史,可用它来构造旧版本数据的查询和用于审计用途归档日志YES

下面来看一下闪回功能的启停:
主要操作步骤如下:

1、数据库处于归档模式
2、开启归档日志
3、设置合理的闪回区
4、开启flashback并检查:alter database flashback on/off;

SQL> shutdown immediate
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> startup mount
ORACLE instance started.

Total System Global Area 1586708480 bytes
Fixed Size		    2213736 bytes
Variable Size		 1090521240 bytes
Database Buffers	  486539264 bytes
Redo Buffers		    7434240 bytes
Database mounted.
SQL>  archive log list;
Database log mode	       No Archive Mode
Automatic archival	       Disabled
Archive destination	       USE_DB_RECOVERY_FILE_DEST
Oldest online log sequence     54
Current log sequence	       56
SQL> alter database archivelog;                         # 注意看下面的 Enabled 和 上面的 Disabled

Database altered.

SQL> select flashback_on from v$database;

FLASHBACK_ON
------------------
NO

SQL>  archive log list;
Database log mode	       Archive Mode
Automatic archival	       Enabled
Archive destination	       USE_DB_RECOVERY_FILE_DEST
Oldest online log sequence     54
Next log sequence to archive   56
Current log sequence	       56
SQL> alter system set db_recovery_file_dest='/home/oracle/app/flash_recovery_area' scope=both;

System altered.

SQL> alter system set db_recovery_file_dest_size=60G scope=both;

System altered.

SQL>  alter system set db_flashback_retention_target=4320 scope=both;

System altered.

SQL>  archive log list;
Database log mode	       Archive Mode
Automatic archival	       Enabled
Archive destination	       USE_DB_RECOVERY_FILE_DEST
Oldest online log sequence     54
Next log sequence to archive   56
Current log sequence	       56
SQL> alter database flashback on;

Database altered.

SQL> select flashback_on from v$database;

FLASHBACK_ON
------------------
YES

SQL>

如上,我们成功开启了数据库的闪回功能,下面我们开始准备闪回所需的数据:

SQL> alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss';

Session altered.

SQL> select sysdate from dual;

SYSDATE
-------------------
2020-09-26 10:19:21

SQL>
SQL> create table test1 (id int,name varchar(16),curtime TIMESTAMP);

Table created.

SQL> insert into test1 values (1,'post',sysdate);

1 row created.

SQL>  insert into test1 values (2,'orac',sysdate);

1 row created.

SQL> insert into test1 values (3,'mysq',sysdate);

1 row created.

SQL> insert into test1 values (4,'redi',sysdate);

1 row created.

SQL>
SQL> set linesize 800
SQL> set pagesize 900                            
SQL>  select * from test1;

	ID NAME 	    CURTIME
---------- ---------------- ----------------------------
	 1 post 	    26-SEP-20 10.20.07.000000 AM
	 2 orac 	    26-SEP-20 10.20.15.000000 AM
	 3 mysq 	    26-SEP-20 10.20.23.000000 AM
	 4 redi 	    26-SEP-20 10.20.32.000000 AM

SQL>

Oracle闪回的使用

闪回使用

闪回查询

闪回查询操作:允许用户查询过去某个时间点的数据,用以重构由于意外删除或更改的数据,但是表中的数据不会变化。于是我们就可以查询过去某个时间点的数据库状态和表中当时的数据。其工作原理为:Oracle 会提取所需要的撤销数据(前提是撤销是可用的,即撤销数据还没被覆盖)进行回滚,但这种回滚是临时的,仅针对当前session可见。

SQL>  select * from test1;

	ID NAME 	    CURTIME
---------- ---------------- ---------------------------------------------------------------------------
	 1 post 	    26-SEP-20 10.20.07.000000 AM
	 2 orac 	    26-SEP-20 10.20.15.000000 AM
	 3 mysq 	    26-SEP-20 10.20.23.000000 AM
	 4 redi 	    26-SEP-20 10.20.32.000000 AM

SQL> commit;

Commit complete.

SQL> select sysdate from dual;

SYSDATE
-------------------
2020-09-26 10:22:29

SQL> delete from test1 where id = 1;

1 row deleted.

SQL> commit;

Commit complete.

SQL> select * from test1;

	ID NAME 	    CURTIME
---------- ---------------- ---------------------------------------------------------------------------
	 2 orac 	    26-SEP-20 10.20.15.000000 AM
	 3 mysq 	    26-SEP-20 10.20.23.000000 AM
	 4 redi 	    26-SEP-20 10.20.32.000000 AM

SQL>
SQL> select * from test1 as of timestamp  to_timestamp('2020-09-26 10:22:29','yyyy-mm-dd hh24:mi:ss');

	ID NAME 	    CURTIME
---------- ---------------- ---------------------------------------------------------------------------
	 1 post 	    26-SEP-20 10.20.07.000000 AM
	 2 orac 	    26-SEP-20 10.20.15.000000 AM
	 3 mysq 	    26-SEP-20 10.20.23.000000 AM
	 4 redi 	    26-SEP-20 10.20.32.000000 AM

SQL>

如上一条被删除的数据就被我们查回来了,但是建议不要使用时间 而是scn:

SQL> select timestamp_to_scn(to_date('2020-09-26 10:22:29','yyyy-mm-dd hh24:mi:ss')) from dual;

TIMESTAMP_TO_SCN(TO_DATE('2020-09-2610:22:29','YYYY-MM-DDHH24:MI:SS'))
----------------------------------------------------------------------
							       2254386

SQL>
SQL> select * from test1  as of scn 2254386;

	ID NAME 	    CURTIME
---------- ---------------- ---------------------------------------------------------------------------
	 1 post 	    26-SEP-20 10.20.07.000000 AM
	 2 orac 	    26-SEP-20 10.20.15.000000 AM
	 3 mysq 	    26-SEP-20 10.20.23.000000 AM
	 4 redi 	    26-SEP-20 10.20.32.000000 AM

SQL> select * from test1 ;

	ID NAME 	    CURTIME
---------- ---------------- ---------------------------------------------------------------------------
	 2 orac 	    26-SEP-20 10.20.15.000000 AM
	 3 mysq 	    26-SEP-20 10.20.23.000000 AM
	 4 redi 	    26-SEP-20 10.20.32.000000 AM

SQL>

如上,这个闪回查询 顾名思义,没有改变现表状态的功能 我们可以很清楚的看到数据不会变化。

闪回表(insert delete update)

闪回表操作:闪回表就是对表的数据做回退,回退到之前的某个时间点(也即:可将某个表回退到过去某个时间点的状态和数据内容)。其工作原理为:和上面一样Oracle会先去查询撤销段,提取过去某个时间点之后的所有变更,构造反转这些变更的SQL语句进行回退。闪回操作是一个单独的事务,所以若由于撤销数据过期之类的原因导致无法闪回,整个操作会回滚,不会存在不一致的状态。它这里利用的也是undo的历史数据,与undo_retention设置有关,默认是1440分钟(1天)。但是sys用户表空间不支持闪回表,示例如下:

SQL>  flashback table test1 to timestamp to_timestamp('2020-09-26 10:22:29','yyyy-mm-dd hh24:mi:ss');
 flashback table test1 to timestamp to_timestamp('2020-09-26 10:22:29','yyyy-mm-dd hh24:mi:ss')
                 *
ERROR at line 1:
ORA-08185: Flashback not supported for user SYS


SQL>

OK,我们换一个用户开始同样的操作:

SQL> CREATE user song identified by sys;

User created.

SQL> show user
USER is "SYS"
SQL> alter user song identified by 123456;

User altered.

SQL> grant connect,resource,dba to song;

Grant succeeded.

SQL> show user
USER is "SYS"
SQL> connect song/123456
Connected.
SQL>

然后我们在其他用户下面执行这个闪回表操作(需要注意的是:要想表闪回,需要允许表启动行迁移(row movement)
),实例如下:

SQL> show user
USER is "SONG"
SQL> alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss';

Session altered.

SQL> select sysdate from dual;

SYSDATE
-------------------
2020-09-26 10:53:01

SQL> create table test1 (id int,name varchar(16),curtime TIMESTAMP);

Table created.

SQL> insert into test1 values (1,'post',sysdate);

1 row created.

SQL> insert into test1 values (2,'orac',sysdate);

1 row created.

SQL> insert into test1 values (3,'mysq',sysdate);

1 row created.

SQL> insert into test1 values (4,'redi',sysdate);

1 row created.

SQL> select * from test1;

	ID NAME 	    CURTIME
---------- ---------------- ---------------------------------------------------------------------------
	 1 post 	    26-SEP-20 10.53.20.000000 AM
	 2 orac 	    26-SEP-20 10.53.28.000000 AM
	 3 mysq 	    26-SEP-20 10.53.36.000000 AM
	 4 redi 	    26-SEP-20 10.53.45.000000 AM

SQL> commit;

Commit complete.

SQL> select sysdate from dual;

SYSDATE
-------------------
2020-09-26 10:54:10

SQL> delete from test1 where id = 1;

1 row deleted.

SQL> commit;

Commit complete.

SQL> select * from test1;

	ID NAME 	    CURTIME
---------- ---------------- ----------------------
	 2 orac 	    26-SEP-20 10.53.28.000000 AM
	 3 mysq 	    26-SEP-20 10.53.36.000000 AM
	 4 redi 	    26-SEP-20 10.53.45.000000 AM

SQL> select * from test1 as of timestamp  to_timestamp('2020-09-26 10:54:10','yyyy-mm-dd hh24:mi:ss');

	ID NAME 	    CURTIME
---------- ---------------- ----------------------
	 1 post 	    26-SEP-20 10.53.20.000000 AM
	 2 orac 	    26-SEP-20 10.53.28.000000 AM
	 3 mysq 	    26-SEP-20 10.53.36.000000 AM
	 4 redi 	    26-SEP-20 10.53.45.000000 AM

SQL> flashback table test1 to timestamp to_timestamp('2020-09-26 10:54:10','yyyy-mm-dd hh24:mi:ss');
flashback table test1 to timestamp to_timestamp('2020-09-26 10:54:10','yyyy-mm-dd hh24:mi:ss')
                *
ERROR at line 1:
ORA-08189: cannot flashback the table because row movement is not enabled


SQL> select row_movement from dba_tables where table_name='test1' and owner='song';

no rows selected

SQL> alter table test1 enable row movement;

Table altered.

SQL> flashback table test1 to timestamp to_timestamp('2020-09-26 10:54:10','yyyy-mm-dd hh24:mi:ss');

Flashback complete.

SQL> select * from test1;

	ID NAME 	    CURTIME
---------- ---------------- ----------------------
	 1 post 	    26-SEP-20 10.53.20.000000 AM
	 2 orac 	    26-SEP-20 10.53.28.000000 AM
	 3 mysq 	    26-SEP-20 10.53.36.000000 AM
	 4 redi 	    26-SEP-20 10.53.45.000000 AM

SQL> alter table test1 disable row movement;

Table altered.

SQL>

如上开启row movement,因为启用表闪回首先要在表上支持行移动(在数据字典中设置标识来标识该操作可能会改变行ID,即同一条数据闪回成功后主键都一样,但行ID其实已经发生变化了)。

闪回表可能会失败,有可能有以下几种情况:

  • 违反了数据库约束:比如用户不小心删除了子表中的数据,现在想利用闪回表技术进行回退,恰好在这中间,父表中与该数据对应的那条记录也被删除了,在这种情况下,由于违反了外键约束,导致闪回表操作失败了
  • 撤销数据失效:比如用于支撑闪回操作的撤销数据被覆盖了,这种情况闪回表操作自然会失败
  • 闪回不能跨越DDL:在闪回点和当前点之间,表结构有过变更,这种情况闪回操作也会失败

注:上述闪回功能都是基于撤销数据(undo log)的,而撤销数据是会被重写的(Expired会被重写,Active不会被重写),所以在需要使用上面闪回功能去恢复数据的时候(确切地说,是需要使用基于撤销数据的闪回功能时),最短时间发现错误,第一时间执行闪回操作,才能最大程度地保证闪回功能的成功

闪回删除

在Oracle中,当一个表被drop掉,表会被放入recyclebin 即:回收站。于是我们这里的drop闪回就可以通过回收站做表的闪回。在闪回过程中 表上的索引、约束等同样会被恢复,同样这里也不支持sys/system用户表空间对象

而回收站功能的开启和关闭是可通过alter system set recyclebin=off; alter system set recyclebin=on scope=spfile;来完成(默认是开启的)示例如下:

SQL> alter database flashback off;

Database altered.

SQL> show recyclebin;                  # 看一眼回收站
ORIGINAL NAME	 RECYCLEBIN NAME		OBJECT TYPE  DROP TIME
---------------- ------------------------------ ------------ -------------------
TEST1		 BIN$sC+Fb/6hJ+3gUAB/AQATZg==$0 TABLE	     2020-09-26:10:52:17
SQL> purge recyclebin;                  # 清空回收站 不影响下面的操作

Recyclebin purged.

SQL> show recyclebin;                  # 回收站为空
SQL> select * from test1;

	ID NAME 	    CURTIME
---------- ---------------- ---------------------------------------------------------------------------
	 1 post 	    26-SEP-20 10.53.20.000000 AM
	 2 orac 	    26-SEP-20 10.53.28.000000 AM
	 3 mysq 	    26-SEP-20 10.53.36.000000 AM
	 4 redi 	    26-SEP-20 10.53.45.000000 AM

SQL> drop table test1;

Table dropped.

SQL> show recyclebin;                  # 表被放到回收站了
ORIGINAL NAME	 RECYCLEBIN NAME		OBJECT TYPE  DROP TIME
---------------- ------------------------------ ------------ -------------------
TEST1		 BIN$sC+Fb/6iJ+3gUAB/AQATZg==$0 TABLE	     2020-09-26:12:24:15
SQL> select sysdate from dual;

SYSDATE
-------------------
2020-09-26 12:24:45

SQL> flashback table TEST1  to before drop;

Flashback complete.

SQL> select * from test1;

	ID NAME 	    CURTIME
---------- ---------------- ---------------------------------------------------------------------------
	 1 post 	    26-SEP-20 10.53.20.000000 AM
	 2 orac 	    26-SEP-20 10.53.28.000000 AM
	 3 mysq 	    26-SEP-20 10.53.36.000000 AM
	 4 redi 	    26-SEP-20 10.53.45.000000 AM

SQL>

如上我们使用purge recyclebin;来清理当前的回收站。这里我们注意一点:在最开始的时候 我可是把flashback关闭了的,但是只要开启了recyclebin,那么就可以闪回DROP表。

但如果连续覆盖,就需要指定恢复的表名,如果已经存在表,则需要恢复重命名。

SQL> select * from test1;

	ID NAME 	    CURTIME
---------- ---------------- ---------------------------------------------------------------------------
	 1 post 	    26-SEP-20 10.53.20.000000 AM
	 2 orac 	    26-SEP-20 10.53.28.000000 AM
	 3 mysq 	    26-SEP-20 10.53.36.000000 AM
	 4 redi 	    26-SEP-20 10.53.45.000000 AM

SQL> drop table test1;

Table dropped.

SQL> create table test1 (id int,mytime timestamp);

Table created.

SQL> insert into test1 values (1,sysdate);

1 row created.

SQL>  drop table test1;

Table dropped.

SQL> show recyclebin;                  # 这个时候回收站里面有两个不一样的同名表
ORIGINAL NAME	 RECYCLEBIN NAME		OBJECT TYPE  DROP TIME
---------------- ------------------------------ ------------ -------------------
TEST1		 BIN$sC+Fb/6kJ+3gUAB/AQATZg==$0 TABLE	     2020-09-26:12:31:23
TEST1		 BIN$sC+Fb/6jJ+3gUAB/AQATZg==$0 TABLE	     2020-09-26:12:30:18
SQL> flashback table "BIN$sC+Fb/6kJ+3gUAB/AQATZg==$0" to before drop ;    # 这样可以恢复指定那个

Flashback complete.

SQL> select * from test1;

	ID MYTIME
---------- ---------------------------------------------------------------------------
	 1 26-SEP-20 12.31.17.000000 PM

SQL> flashback table test1 to before drop rename to another_test1;     # 恢复的时候 同时做了个重命名

Flashback complete.

SQL> select * from another_test1;

	ID NAME 	    CURTIME
---------- ---------------- ---------------------------------------------------------------------------
	 1 post 	    26-SEP-20 10.53.20.000000 AM
	 2 orac 	    26-SEP-20 10.53.28.000000 AM
	 3 mysq 	    26-SEP-20 10.53.36.000000 AM
	 4 redi 	    26-SEP-20 10.53.45.000000 AM

SQL>

闪回数据库(truncate/多表数据变更)

数据库闪回功能可以基于两种方式来完成:1、数据库闪回必须在mounted状态下进行 ; 2、基于快照的可以在open下进行闪回库 (要求数据库为归档模式)。

闪回数据库主要是将数据库还原到过去的某个时间点或SCN,用于数据库出现逻辑错误时,需要open database resetlogs。当然,闪回点之后的所有工作就丢失了,其实就相当于数据库的不完整恢复,所以只能以resetlogs模式打开数据库。闪回数据库会造成停机时间,当然相比于传统备份恢复机制,恢复过程会快很多。其工作原理为:闪回数据库不使用撤销数据(undo log),使用另外一种机制来保留回退所需要的恢复数据。当启用闪回数据库时,发生变化的数据块会不断从数据库缓冲区缓存中复制到闪回缓冲区,然后被称为恢复写入器(Recovery Writer)的后台进程会将这些数据刷新到磁盘中的闪回日志文件中。闪回的过程:是一个 提取闪回日志 将块映像复制回数据文件 的过程。

虽然在上面我们已经配置过闪回数据库的一些属性,但是这个很重要,下面再来详细看一下闪回数据库功能的配置:
主要操作步骤如下:

1、数据库处于归档模式 startup mount
2、开启归档日志 alter database archivelog;
3、设置合理的闪回区 指定闪回恢复区 指定恢复区大小 指定闪回日志保存时间
指定闪回恢复区,也就是存放闪回日志的位置,但闪回恢复区不仅仅是为了存放闪回日志。Oracle的很多备份恢复技术都用到这个区域,比如控制文件的自动备份等都会存放到此区域
alter system set db_recovery_file_dest='/home/oracle/app/flash_recovery_area' scope=both;
指定恢复区大小
alter system set db_recovery_file_dest_size=60G scope=both;
指定闪回日志保留时间为4320 / 60 = 72小时,即通过闪回操作,可以将数据库回退到前72小时内的任意时间点
alter system set db_flashback_retention_target=4320 scope=both;

4、开启flashback并检查:alter database flashback on/off;

下面是详细的SQL演示:

SQL> shutdown immediate                      # 因为当前用户是song 不是sys  没有权限
ORA-01031: insufficient privileges
SQL> conn /as sysdba                      # 连接 用sys用户
Connected.
SQL> shutdown immediate                      # 关闭数据库
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> startup mount                      # 开启mounted状态
ORACLE instance started.

Total System Global Area 1586708480 bytes
Fixed Size		    2213736 bytes
Variable Size		 1090521240 bytes
Database Buffers	  486539264 bytes
Redo Buffers		    7434240 bytes
Database mounted.
SQL> archive log list;             # 查看归档日志参数
Database log mode	       Archive Mode
Automatic archival	       Enabled
Archive destination	       USE_DB_RECOVERY_FILE_DEST
Oldest online log sequence     58
Next log sequence to archive   60
Current log sequence	       60
SQL> alter database archivelog;            # 开启归档日志

Database altered.

SQL> archive log list;
Database log mode	       Archive Mode
Automatic archival	       Enabled
Archive destination	       USE_DB_RECOVERY_FILE_DEST
Oldest online log sequence     58
Next log sequence to archive   60
Current log sequence	       60
SQL>  select flashback_on from v$database;                 # 查看闪回是否开启

FLASHBACK_ON
------------------
NO

SQL>                       # 下面是配置闪回属性
SQL> alter system set db_recovery_file_dest='/home/oracle/app/flash_recovery_area' scope=both;

System altered.

SQL> alter system set db_recovery_file_dest_size=60G scope=both;

System altered.

SQL> alter system set db_flashback_retention_target=4320 scope=both;

System altered.

SQL> archive log list;
Database log mode	       Archive Mode
Automatic archival	       Enabled
Archive destination	       USE_DB_RECOVERY_FILE_DEST
Oldest online log sequence     58
Next log sequence to archive   60
Current log sequence	       60
SQL>  alter database flashback on;       # 开启闪回

Database altered.

SQL> select flashback_on from v$database;        # 查看 是开启的

FLASHBACK_ON
------------------
YES

SQL> alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss';         # 设置时间格式

Session altered.

SQL> select sysdate from dual;

SYSDATE
-------------------
2020-09-27 10:55:26

SQL> select * from test1;
select * from test1
              *
ERROR at line 1:
ORA-01219: database not open: queries allowed on fixed tables/views only


SQL> alter database open;                # 打开数据库

Database altered.

SQL> select * from test1;

	ID NAME 	    CURTIME
---------- ---------------- ---------------------------------------------------------------------------
	 2 orac 	    26-SEP-20 10.20.15.000000 AM
	 3 mysq 	    26-SEP-20 10.20.23.000000 AM
	 4 redi 	    26-SEP-20 10.20.32.000000 AM

SQL> connect song/123456                      # 使用自定义用户连接
Connected.
SQL> select * from another_test1;

	ID NAME 	    CURTIME
---------- ---------------- ---------------------------------------------------------------------------
	 1 post 	    27-SEP-20 02.05.11.000000 PM
	 2 orac 	    27-SEP-20 02.06.02.000000 PM
	 3 mysq 	    27-SEP-20 02.06.02.000000 PM
	 4 redi 	    27-SEP-20 02.06.35.000000 PM

SQL>

如下是闪回数据库的实例:

SQL> connect /as sysdba
Connected to an idle instance.
SQL>  startup
ORACLE instance started.

Total System Global Area 1586708480 bytes
Fixed Size		    2213736 bytes
Variable Size		 1090521240 bytes
Database Buffers	  486539264 bytes
Redo Buffers		    7434240 bytes
Database mounted.
Database opened.
SQL> connect song/123456
Connected.
SQL> select table_name from dba_tables where owner = 'SONG';

TABLE_NAME
------------------------------
SHANHUI
SYS_TEMP_FBT
ANOTHER_TEST1

SQL> select * from ANOTHER_TEST1;

	ID NAME
---------- ----------------
CURTIME
---------------------------------------------------------------------------
	 1 post
27-SEP-20 02.05.11.000000 PM

	 2 orac
27-SEP-20 02.06.02.000000 PM

	 3 mysq
27-SEP-20 02.06.02.000000 PM


	ID NAME
---------- ----------------
CURTIME
---------------------------------------------------------------------------
	 4 redi
27-SEP-20 02.06.35.000000 PM


SQL> set linesize 800
SQL> alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss';

Session altered.

SQL> select sysdate from dual;

SYSDATE
-------------------
2020-09-27 14:29:26

SQL> truncate table ANOTHER_TEST1;

Table truncated.

SQL> select * from ANOTHER_TEST1;

no rows selected

SQL> commit;

Commit complete.

SQL> connect /as sysdba
Connected.
SQL> shutdown immediate;
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> startup mount;
ORACLE instance started.

Total System Global Area 1586708480 bytes
Fixed Size		    2213736 bytes
Variable Size		 1090521240 bytes
Database Buffers	  486539264 bytes
Redo Buffers		    7434240 bytes
Database mounted.
SQL> flashback database to timestamp to_timestamp('2020-09-27 14:29:26','yyyy-mm-dd HH24:MI:SS');

Flashback complete.

SQL> alter database open resetlogs;

Database altered.

SQL> conn song/123456
Connected.
SQL> select * from ANOTHER_TEST1;

	ID NAME 	    CURTIME
---------- ---------------- ---------------------------------------------------------------------------
	 1 post 	    27-SEP-20 02.05.11.000000 PM
	 2 orac 	    27-SEP-20 02.06.02.000000 PM
	 3 mysq 	    27-SEP-20 02.06.02.000000 PM
	 4 redi 	    27-SEP-20 02.06.35.000000 PM

SQL> show user
USER is "SONG"
SQL>

如上,在闪回完成之后,还需要注意的是:闪回数据库主要是将数据库还原值过去的某个时间点或SCN,用于数据库出现逻辑错误时,千万不能忘记open database resetlogs

在上面我们也曾说过:闪回数据库的功能 也是 可以基于快照来实现。即:创建闪回快照点,然后恢复到指定的快照点。示例如下:

SQL> select * from ANOTHER_TEST1;

	ID NAME 	    CURTIME
---------- ---------------- ---------------------------------------------------------------------------
	 1 post 	    27-SEP-20 02.05.11.000000 PM
	 2 orac 	    27-SEP-20 02.06.02.000000 PM
	 3 mysq 	    27-SEP-20 02.06.02.000000 PM
	 4 redi 	    27-SEP-20 02.06.35.000000 PM

SQL> create restore point myfirstpoint guarantee flashback database;
create restore point myfirstpoint guarantee flashback database
*
ERROR at line 1:
ORA-01031: insufficient privileges


SQL> conn /as sysdba
Connected.
SQL> create restore point myfirstpoint guarantee flashback database; # 创建闪回快照点

Restore point created.

SQL> conn song/123456
Connected.
SQL> select * from another_test1;

	ID NAME 	    CURTIME
---------- ---------------- ---------------------------------------------------------------------------
	 1 post 	    27-SEP-20 02.05.11.000000 PM
	 2 orac 	    27-SEP-20 02.06.02.000000 PM
	 3 mysq 	    27-SEP-20 02.06.02.000000 PM
	 4 redi 	    27-SEP-20 02.06.35.000000 PM

SQL> truncate table another_test1;

Table truncated.

SQL> commit;

Commit complete.

SQL> conn /as sysdba
Connected.
SQL> shutdown immediate;
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> startup mount;
ORACLE instance started.

Total System Global Area 1586708480 bytes
Fixed Size		    2213736 bytes
Variable Size		 1090521240 bytes
Database Buffers	  486539264 bytes
Redo Buffers		    7434240 bytes
Database mounted.
SQL> flashback database to restore point myfirstpoint; # 基于快照点,开始闪回

Flashback complete.

SQL> alter database open resetlogs;

Database altered.

SQL> show user
USER is "SYS"
SQL> conn song/123456
Connected.
SQL> select * from another_test1;

	ID NAME 	    CURTIME
---------- ---------------- ---------------------------------------------------------------------------
	 1 post 	    27-SEP-20 02.05.11.000000 PM
	 2 orac 	    27-SEP-20 02.06.02.000000 PM
	 3 mysq 	    27-SEP-20 02.06.02.000000 PM
	 4 redi 	    27-SEP-20 02.06.35.000000 PM

SQL>
SQL> select flashback_on from v$database;

FLASHBACK_ON
------------------
YES

SQL> archive log list;
ORA-01031: insufficient privileges
SQL> conn /as sysdba
Connected.
SQL> archive log list;
Database log mode	       Archive Mode
Automatic archival	       Enabled
Archive destination	       USE_DB_RECOVERY_FILE_DEST
Oldest online log sequence     1
Next log sequence to archive   1
Current log sequence	       1
SQL>
SQL>  select NAME,OPEN_MODE ,DATABASE_ROLE,CURRENT_SCN,FLASHBACK_ON from v$database;

NAME	  OPEN_MODE	       DATABASE_ROLE	CURRENT_SCN FLASHBACK_ON
--------- -------------------- ---------------- ----------- ------------------
ORCL	  READ WRITE	       PRIMARY		    2364180 YES

SQL> show user
USER is "SYS"
SQL> select to_char(systimestamp,'yyyy-mm-dd HH24:MI:SS') as sysdt , dbms_flashback.get_system_change_number scn from dual;

SYSDT			   SCN
------------------- ----------
2020-09-27 15:52:26    2364190

SQL>  select * from V$FLASHBACK_DATABASE_LOG; # 查看数据库可恢复的时间点

OLDEST_FLASHBACK_SCN OLDEST_FL RETENTION_TARGET FLASHBACK_SIZE ESTIMATED_FLASHBACK_SIZE
-------------------- --------- ---------------- -------------- ------------------------
	     2328783 27-SEP-20		   4320       31883264		      388988928

SQL>

闪回数据归档

闪回数据归档:使得表具有回退到过去任何时间点的能力(前面提到的闪回查询、闪回表都会受限于撤销数据是否失效,如果撤销数据被覆盖重写了,闪回操作自然会失败;闪回删除则受限于表空间是否有足够可用空间) 而闪回数据归档,则没有这些限制。

该功能实现的步骤如下:

1、创建一个用户闪回数据归档的表空间
2、创建一个保留时间为一定时间的闪回归档
3、为某一个表启用闪回归档

示例如下:

SQL> show user
USER is "SYS"
SQL> conn song/123456
Connected.
SQL> select * from another_test1;

	ID NAME 	    CURTIME
---------- ---------------- ---------------------------------------------------------------------------
	 1 post 	    27-SEP-20 02.05.11.000000 PM
	 2 orac 	    27-SEP-20 02.06.02.000000 PM
	 3 mysq 	    27-SEP-20 02.06.02.000000 PM
	 4 redi 	    27-SEP-20 02.06.35.000000 PM

# 创建一个用户闪回数据归档的表空间
SQL> create tablespace another_test1 datafile 'test1.dbf' size 20m;

Tablespace created.

# 创建一个保留时间为一年时间的闪回归档
SQL> create flashback archive test1_flahback_archive tablespace another_test1 retention 1 year;

Flashback archive created.

# 赋予用户归档的权限
SQL> grant flashback archive on test1_flahback_archive to song;

Grant succeeded.

# 为 another_test1 表启用闪回归档
SQL> alter table another_test1 flashback archive test1_flahback_archive;

Table altered.

SQL> select * from another_test1;

	ID NAME 	    CURTIME
---------- ---------------- ---------------------------------------------------------------------------
	 1 post 	    27-SEP-20 02.05.11.000000 PM
	 2 orac 	    27-SEP-20 02.06.02.000000 PM
	 3 mysq 	    27-SEP-20 02.06.02.000000 PM
	 4 redi 	    27-SEP-20 02.06.35.000000 PM

# 查哪些表已经启用了闪回数据归档
SQL> select table_name from dba_flashback_archive_tables;

TABLE_NAME
------------------------------
ANOTHER_TEST1

SQL> set line 300
SQL> col FLASHBACK_ARCHIVE_NAME for a50
SQL> col tablespace_name for a50
SQL> col quota_in_mb for a50

# 查看有关闪回数据归档所使用的表空间的信息
SQL> select flashback_archive_name,tablespace_name,quota_in_mb from dba_flashback_archive_ts;

FLASHBACK_ARCHIVE_NAME				   TABLESPACE_NAME				      QUOTA_IN_MB
-------------------------------------------------- -------------------------------------------
TEST1_FLAHBACK_ARCHIVE				   ANOTHER_TEST1

SQL> # 查询数据库中所有的闪回数据归档
SQL> select flashback_archive_name,retention_in_days from dba_flashback_archive;

FLASHBACK_ARCHIVE_NAME				   RETENTION_IN_DAYS
-------------------------------------------------- -----------------
TEST1_FLAHBACK_ARCHIVE						 365

SQL>

取消对于数据表的闪回归档可以使用如下命令:

alter table table_name no flashback archive;

下面来实际操作一下闪回数据归档 首先记录一下SCN,从数据库表中删除部分数据:

原表数据内容如下:

SQL> select * from another_test1;

	ID NAME 	    CURTIME
---------- ---------------- ---------------------------------------------------------------------------
	 1 post 	    27-SEP-20 02.05.11.000000 PM
	 2 orac 	    27-SEP-20 02.06.02.000000 PM
	 3 mysq 	    27-SEP-20 02.06.02.000000 PM
	 4 redi 	    27-SEP-20 02.06.35.000000 PM

SQL>

通过闪回查询如下:

SQL>  select dbms_flashback.get_system_change_number from dual;

GET_SYSTEM_CHANGE_NUMBER
------------------------
		 2367563

SQL> delete from another_test1 where id <= 2;

2 rows deleted.

SQL> commit;

Commit complete.

SQL> select count(*) from another_test1 as of scn 2367563;

  COUNT(*)
----------
	 4

SQL>

其查询计划如下:

SQL> explain plan for select count(*) from another_test1 as of scn 2367563;

Explained.

SQL> select count(*) from another_test1 as of scn 2367563;

  COUNT(*)
----------
	 4

SQL> select * from table(dbms_xplan.display());

PLAN_TABLE_OUTPUT
--------------------------------------
Plan hash value: 3878810653

----------------------------------------------------------------------------
| Id  | Operation	   | Name	   | Rows  | Cost (%CPU)| Time	   |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |		   |	 1 |	 6   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE    |		   |	 1 |		|	   |
|   2 |   TABLE ACCESS FULL| ANOTHER_TEST1 |	 4 |	 6   (0)| 00:00:01 |
----------------------------------------------------------------------------

9 rows selected.

SQL> 

接下来执行一段代码,使UNDO数据老化并覆盖。之后再来看一下闪回数据归档发挥作用的闪回查询,通过执行计划能够看到和之前查询执行方式的不同:

SQL> begin
	delete from another_test1 where rownum < 2;
	commit;
	end;
	/  2    3    4    5  

PL/SQL procedure successfully completed.

SQL> select * from another_test1;

	ID NAME 					      CURTIME
---------- -------------------------------------------------- --------------------------------------------
	 4 redi 					      27-SEP-20 02.06.35.000000 PM

SQL> select count(*) from another_test1 as of scn 2367563;

  COUNT(*)
----------
	 4

SQL> explain plan for select count(*) from another_test1 as of scn 2367563;

Explained.

SQL> select * from table(dbms_xplan.display());

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------
Plan hash value: 1720804579

----------------------------------------------------------------------------------------------------------
| Id  | Operation		  | Name	       | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT	  |		       |     1 |       |    13	 (8)| 00:00:01 |       |       |
|   1 |  SORT AGGREGATE 	  |		       |     1 |       |	    |	       |       |       |
|   2 |   VIEW			  |		       |     3 |       |    13	 (8)| 00:00:01 |       |       |
|   3 |    UNION-ALL		  |		       |       |       |	    |	       |       |       |
|   4 |     PARTITION RANGE SINGLE|		       |     2 |    52 |     3	 (0)| 00:00:01 |     1 |     1 |
|*  5 |      TABLE ACCESS FULL	  | SYS_FBA_HIST_75607 |     2 |    52 |     3	 (0)| 00:00:01 |     1 |     1 |

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------
|*  6 |     FILTER		  |		       |       |       |	    |	       |       |       |
|*  7 |      HASH JOIN OUTER	  |		       |     1 |  2040 |    10	(10)| 00:00:01 |       |       |
|*  8 |       TABLE ACCESS FULL   | ANOTHER_TEST1      |     1 |    12 |     6	 (0)| 00:00:01 |       |       |
|*  9 |       TABLE ACCESS FULL   | SYS_FBA_TCRV_75607 |     2 |  4056 |     3	 (0)| 00:00:01 |       |       |
----------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   5 - filter("ENDSCN">2367563 AND "ENDSCN"<=2367777 AND ("STARTSCN" IS NULL OR "STARTSCN"<=2367563))
   6 - filter("STARTSCN"<=2367563 OR "STARTSCN" IS NULL)

PLAN_TABLE_OUTPUT
----------------------------------------------------------
   7 - access("T".ROWID=CHARTOROWID("RID"(+)))
   8 - filter("T"."VERSIONS_STARTSCN" IS NULL)
   9 - filter(("ENDSCN"(+) IS NULL OR "ENDSCN"(+)>2367777) AND ("STARTSCN"(+) IS NULL OR
	      "STARTSCN"(+)<2367777))

Note
-----
   - dynamic sampling used for this statement (level=2)

30 rows selected.

SQL>

通过以上执行计划可以看到,查询闪回来自SYS_FBA_TCRV_75607系统表,该表隶属于闪回归档表空间,用于记录闪回数据:

SQL> set linesize 100
SQL> desc SYS_FBA_TCRV_75607
 Name						       Null?	Type
 ----------------------------------------------------- -------- ------------------------------------
 RID								VARCHAR2(4000)
 STARTSCN							NUMBER
 ENDSCN 							NUMBER
 XID								RAW(8)
 OP								VARCHAR2(1)

SQL> select count(*) from SYS_FBA_TCRV_75607;

  COUNT(*)
----------
	 3

SQL> select * from SYS_FBA_TCRV_75607;

RID		       STARTSCN     ENDSCN XID		    O
-------------------- ---------- ---------- ---------------- -
AAASe9AAEAAAAI/AAA	2367600 	   06000C0004060000
AAASe9AAEAAAAI/AAB	2367600 	   06000C0004060000
AAASe9AAEAAAAI/AAC	2368015 	   08001F0001060000

SQL> 

闪回功能生成的字典对象有多个,通过查询USER_TABLES / USER_OBJECTS视图可以获得这些对象的详细信息:

SQL> select table_name,tablespace_name from user_tables where table_name like '%FBA%';

TABLE_NAME		       TABLESPACE_NAME
------------------------------ --------------------------------------------------
SYS_FBA_DDL_COLMAP_75607   ANOTHER_TEST1
SYS_FBA_TCRV_75607	       ANOTHER_TEST1
SYS_FBA_HIST_75607

SQL> select object_name,object_type from user_objects where object_name like '%FBA%';

OBJECT_NAME		       OBJECT_TYPE
------------------------------ -------------------
SYS_FBA_TCRV_IDX_75607	       INDEX
SYS_FBA_TCRV_75607	      	   TABLE
SYS_FBA_HIST_75607	           TABLE PARTITION
SYS_FBA_HIST_75607	           TABLE
SYS_FBA_DDL_COLMAP_75607       TABLE

SQL>

还可以通过数据字典视图来查看关于闪回归档表的记录:

SQL> select * from user_flashback_archive_tables;

TABLE_NAME		       OWNER_NAME		      FLASHBACK_ARCHIVE_NAME			ARCHIVE_TABLE_NAME			STATUS
------------------------------------------------------------ ---------------------------------------------- ---------
ANOTHER_TEST1		       SONG			      TEST1_FLAHBACK_ARCHIVE			SYS_FBA_HIST_75607			ENABLED

SQL>

# 可以通过dict字典查询和闪回归档有关的数据字典表
SQL> select table_name from dict where table_name like '%FLASHBACK_ARCHIVE%';

TABLE_NAME
------------------------------
DBA_FLASHBACK_ARCHIVE
DBA_FLASHBACK_ARCHIVE_TABLES
DBA_FLASHBACK_ARCHIVE_TS
USER_FLASHBACK_ARCHIVE
USER_FLASHBACK_ARCHIVE_TABLES

SQL>

本文小结:

闪回查询 包括基本闪回查询,闪回表等技术都依赖于撤销数据(还有一类闪回技术为闪回事务,可以对指定事务进行闪回操作,原理类似,借助于撤销数据来构建用于反转事务的SQL语句),依赖于撤销数据,则自然受限于撤销数据的保留时间,可能会由于撤销数据被覆写而导致闪回失败


闪回删除 则是由于10g版本后对表的删除仅表现为一个rename操作,引入回收站的概念,但此回收站仅是当前表空间的一块逻辑划分,所以会受限于当前表空间的可用空间的限制


闪回归档 可提供查询或回退到过去任意时间点的功能


闪回数据库 则是一中更极端的数据库恢复功能,相当于不完整恢复,依赖于闪回日志

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孤傲小二~阿沐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值