Oracle闪回技术详解及应用

    闪回技术是除了传统备份/恢复之外,Oracle所提供的额外一系列数据保护特性。利用闪回技术,你可以快速查找数据的历史版本,撤销误操作。比起从备份中恢复,闪回操作要简单许多,不通过还原备份就可以将整库回退到指定时间点等。闪回的恢复级别从行级、表级、数据库级均有覆盖。熟练掌握闪回技术可以帮助我们快速解决各种级别的数据问题。

Oracle闪回技术分为以下7类:

一、闪回查询(Flashback Query)

二、闪回版本查询(Flashback Version Query)

三、闪回事务查询(Flashback Transaction Query)

四、闪回事务(Flashback Transaction)

五、闪回表(Flashback Table)

六、闪回删除(Flashback Drop)

七、闪回数据库(Flashback Database)



其中闪回数据库(Flashback Database)属于物理层面特性,其他六项都属于逻辑层面特性。下面将依次演示各项闪回技术。

一、闪回查询(Flashback Query)

闪回查询即我们可以在select语句种通过as of子句指定一个历史的时间点或SCN(System Change Number系统变更号),从而查询数据在这个时间点的状态。闪回查询特别适合恢复错误的数据更新/删除,或者通过阶段性的对比观察数据的变化。如果一个表需要能够闪回查询至很久之前(例如5年,10年前甚至永久),可以开启额外的闪回归档(Flashback archive)来存储数据。

闪回查询示例:

我们以HR.employees这张表来演示闪回查询,假设员工ID为206的记录被不小心误删除且已经commit:

Oracle闪回技术详解及应用_第1张图片

 此时,我们查询ID为206的员工是不存在的,但是通过as of子句我们可以指定一个历史时间点(比数据误删早一点)或者SCN(提前记录v$database.current_scn的值),我们可以将删除前的数据查出来,后续可以通过insert来撤销误删操作。

select * from employees where employee_id=206;
select * from employees as of timestamp to_timestamp('2021-12-17 02:12:43', 'YYYY-MM-DD HH:MI:SS') where employee_id=206;  -- 通过时间点闪回查询
select * from employees as of scn 1634376 where employee_id=206; -- 通过SCN闪回查询

Oracle闪回技术详解及应用_第2张图片

闪回查询可以快速恢复近期的误操作,还有一个常见的用途是我们可以利用闪回查询建立历史版本的视图,方便观察数据变化,例如下面的语句利用闪回查询创建了employees表1小时前的版本视图。

create view hour_ago as select * from employees as of timestamp (systimestamp - interval '60' minute);

二、闪回版本查询(Flashback Version Query)

闪回版本查询用法和闪回查询类似,闪回查询是返回某一时间点的数据状态,而闪回版本查询则是返回一段时间内数据的所有版本。我们可以用select的versions between子句,通过指定SCN或timestamp时间段来查询一段时间内数据的所有版本(当事务提交的时候,会生成数据的一个版本)。

闪回版本查询示例:

我们依次执行下面2条update语句更新ID为206员工的first_name,并且提交事务。

update employees set first_name='Vincent' where employee_id=206;
commit;
update employees set first_name='Victor' where employee_id=206;
commit;

Oracle闪回技术详解及应用_第3张图片

通过我们预先记录的SCN进行闪回版本查询,我们可以发现在first_name的三个版本全部都查询了出来,William(原始版本) => Vincent => Victor。

select * from employees versions between scn 1693319 and 1693644  where employee_id=206;

Oracle闪回技术详解及应用_第4张图片

 通过指定时间段的方式也可以获得相同的结果:

select * from employees 
versions between timestamp to_timestamp('2021-12-17 02:59:45', 'YYYY-MM-DD HH24:MI:SS') and to_timestamp('2021-12-17 03:03:17', 'YYYY-MM-DD HH24:MI:SS')
where employee_id=206;

三、闪回事务查询(Flashback Transaction Query)

闪回事务查询是通过数据字典视图flashback_transaction_query来查询历史事务相关元数据,并且可以通过该视图的undo_sql字段会给出相应的SQL从逻辑层面撤销事务。要使用flashback_transaction_query查询事务信息首先要打开附加日志记录事务信息:

alter database add supplemental log data;

下面对hr.employees依次开启两个事务,一个update,一个delete.

update hr.employees set salary=10000 where employee_id=206;
commit;

delete from hr.employees where employee_id=206;
commit;

Oracle闪回技术详解及应用_第5张图片

查询事务的详细信息:

我们可以通过闪回版本查询找出hr.employees在一定时间段内的事务ID(XID),并通过XID查询 flashback_transaction_query视图找出对应事务的详细信息。

SELECT *
FROM flashback_transaction_query
WHERE xid IN (
  SELECT versions_xid FROM hr.employees VERSIONS BETWEEN TIMESTAMP
  TO_TIMESTAMP('2021-12-17 21:10:57', 'YYYY-MM-DD HH24:MI:SS') AND
  TO_TIMESTAMP('2021-12-17 21:17:57', 'YYYY-MM-DD HH24:MI:SS')      -- where employee_id=206 可以通过更精确的条件限定查询指定行上的事务
);

Oracle闪回技术详解及应用_第6张图片

flashback_transaction_query各列含义:

列名 数据类型 描述
XID RAW(8) 事务标识符
START_SCN NUMBER 事务起始SCN
START_TIMESTAMP DATE 事务起始时间戳
COMMIT_SCN NUMBER 事务终止SCN
(null
代表事务正在运行)
COMMIT_TIMESTAMP DATE 事务终止时间戳
(null代表事务正在运行)
LOGON_USER VARCHAR2(30) 事务执行的用户
UNDO_CHANGE# NUMBER Undo系统变更号
OPERATION VARCHAR2(32) 事务操作类型
TABLE_NAME VARCHAR2(256) 事务应用的表名
TABLE_OWNER VARCHAR2(32) 表的所属用户
ROW_ID VARCHAR2(19) 被事务修改记录的ROWID
UNDO_SQL VARCHAR2(4000) 事务对应的撤销SQL

通过undo_sql撤销事务:

查询结果的UNDO_SQL字段提供了相应SQL来撤销该事务。

Oracle闪回技术详解及应用_第7张图片

 将UNDO_SQL拷贝出来按提交倒叙撤销事务(执行事务时我们是先update后delete,撤销事务时先insert再update):

insert into "HR"."EMPLOYEES"("EMPLOYEE_ID","FIRST_NAME","LAST_NAME","EMAIL","PHONE_NUMBER","HIRE_DATE","JOB_ID","SALARY","COMMISSION_PCT","MANAGER_ID","DEPARTMENT_ID") values ('206','Victor','Gietz','WGIETZ','515.123.8181',TO_DATE('07-6¿  -02', 'DD-MON-RR'),'AC_ACCOUNT','10000',NULL,'205','110');


Oracle闪回技术详解及应用_第8张图片

update "HR"."EMPLOYEES" set "SALARY" = '8300' where ROWID = 'AAAWZpAAKAAAADPAAJ';
commit;

Oracle闪回技术详解及应用_第9张图片

 注意undo_sql是逻辑撤销事务影响,但物理层面上,数据行可能会和以前不同。例如:在撤销delete时,当数据被undo而insert回表时,其物理rowid可能会发生变化。

四、闪回事务(Flashback Transaction)

闪回事务是利用存储过程dbms_flashback.transaction_backout 来回滚某个事务。其回退的原理是利用undo日志逻辑撤销事务的影响,并根据选项决定是否一并撤销依赖其的子事务。

闪回事务有一定的限制条件:

1. 表的结构不能改变(事务提交后未对表进行DDL变更)。

2. 事务中不能使用大字段类型(bfile/blob/clob/nclob)。

3. 无法是用LogMiner不支持的特性。

因为事务之前可能存在依赖性,dbms_flashback.transaction_backout可以通过选项来控制是否一同闪回其依赖事务。

dbms_flashback.transaction_backout语法:

DBMS_FLASHBACK.TRANSACTION_BACKOUT
   numtxns            NUMBER,
   xids               XID_ARRAY,                     -- 通过事务ID列表来闪回
   options            NUMBER default NOCASCADE,      -- 闪回选项,取值可以为cascade/nocascade/nocascade_force/nonconflict_only
   timeHint           TIMESTAMP default MINTIME);    -- timeHint可以替换为scnhint,提示事务开始前的时间或SCN

DBMS_FLASHBACK.TRANSACTION_BACKOUT
   numtxns           NUMBER,
   txnnames          TXNAME_ARRAY,              -- 通过事务名称列表来闪回
   options           NUMBER default NOCASCADE,  -- 闪回选项,取值可以为cascade/nocascade/nocascade_force/nonconflict_only
   timehint          TIMESTAMP MINTIME );       -- timeHint可以替换为scnhint,提示事务开始前的时间或SCN

关于dbms_flashback.transaction_backout需要重点注意的是第三项options的值,4个选项的含义如下:

  • cascade, 递归闪回其子事务,如果未使用选项而发现有依赖其的子事务,则闪回失败。
  • nocascade, 默认值,按照没有依赖子事务进行闪回,如果碰到依赖的子事务,则闪回失败。
  • nocascade_force,忽略子事务,强行闪回指定事务,如果结果未违反约束,你可以选择提交或回滚闪回操作。
  • nonconflict_only, 只闪回事务中不违反约束的行,会破坏事务的原子性(慎用)。

闪回事务示例:

employees表中employee_id为206的记录示例,salary初始值为10000,第一个事务更新为1000,第二个事务在第一个事务基础上将salary乘以2(依赖事务)。

Oracle闪回技术详解及应用_第10张图片

 首先通过闪回版本查询,找到记录206在近期的所有事务ID(XID),SCN较小的update即第一个事务。

SELECT xid,commit_scn,commit_timestamp,operation
FROM flashback_transaction_query
WHERE xid IN (
  SELECT versions_xid FROM hr.employees VERSIONS BETWEEN TIMESTAMP
  TO_TIMESTAMP('2021-12-18 03:35:58', 'YYYY-MM-DD HH24:MI:SS') AND
  TO_TIMESTAMP('2021-12-18 03:37:58', 'YYYY-MM-DD HH24:MI:SS')
  where employee_id=206);  -- 指定查询该条记录上的事务。

Oracle闪回技术详解及应用_第11张图片

 通过找到的XID(示例中为'0A00000062050000'),先用默认的选项闪回(nocascade)。因为第二个事务在第一个事务基础上将salary值乘2(闪回的目标事务存在被依赖关系),因此无法单独闪回第一个事务,执行报错。

Oracle闪回技术详解及应用_第12张图片

 将选项设置为dbms_flashback.cascade,Oracle会先闪回子事务,再闪回目标事务。可以看到salary值恢复到了初始值10000,事务1和事务2的效果全部都消失了。

Oracle闪回技术详解及应用_第13张图片

闪回事务后,系统并不会自动提交(依然会占有锁,其他会话看不到闪回结果)。 通过查询闪回后的结果,我们发现结果已经恢复到了原始状态,需要显式提交让结果持久化。

以上即是闪回单个事务的示例,多个事务的闪回只需要将xids参数用逗号分隔,numtxns修改为要闪回的事务数量即可。

五、闪回表(Flashback Table)

闪回表的原理是利用undo日志,将整张表回退到某个时间点/SCN/restore_point。该时间点之后的所有变更都会被撤销,而数据库其他的部分不受影响。

闪回的表需要满足的以下前提条件:

  • 表的类型不能是:物化视图、聚簇的一部分、分区表的一部分、系统表、数据字典视图、远程表、嵌套表等。
  • 表结构不能变更过。
  • 表的行移动必须打开(row movement)。
  • undo日志必须能覆盖到闪回的时间点,如果时间太久,undo已被覆盖,则闪回可能失败。

闪回表示例:

以employees表示例,初始表中有107行数据,每个员工的salary都不同。

Oracle闪回技术详解及应用_第14张图片

 一个事务删除了一行,且更新时未加where条件将salary全部更新为1:

Oracle闪回技术详解及应用_第15张图片

当表上运行了很多事务,采用闪回事务的方式可能相当繁琐,而闪回表则是更好的选择。

首先打开行移动:

alter table hr.employees enable row movement;

 执行flashback table命令,可以指定时间点、SCN、或restore point

flashback table hr.employees to scn 1759231;

Oracle闪回技术详解及应用_第16张图片

 如果事先未记录SCN,也可以用时间戳闪回至错误发生前:

flashback table hr.employees to timestamp to_timestamp('2021-12-18 03:37:58', 'YYYY-MM-DD HH24:MI:SS');

或使用还原点闪回表:

创建一个普通before_update还原点:

create restore point before_update;

闪回至之前创建的还原点:

flashback table hr.employees to restore point before_update;

还原点可以在一些敏感操作前事先使用create restore point语句建立,方便出错回退。

六、闪回删除(Flashback Drop)

闪回删除是用来撤销drop table语句的,其原理和windows的回收站相同。当执行drop table语句时,oracle并不会将表删除,而是将表及相关对象重命名并放入回收站。回收站中的对象可以像普通表一样查询。

闪回删除示例:

先创建表t,删除,再创建同名表t,再删除(drop table前会隐式提交数据,因此数据也会在回收站中查到):

Oracle闪回技术详解及应用_第17张图片

 Oracle闪回技术详解及应用_第18张图片

使用show recyclebin;我们就可以查看当前回收站中的表,可以看到表的original_name都是T:

show recyclebin;

 我们可以像查询普通表一样查询回收站中的对象:

Oracle闪回技术详解及应用_第19张图片

当存在同名表时,使用表名默认会闪回最后drop的表,我们可以用回收站中的对象名指定闪回对象,并可以选择性的进行重命名。

将第一次drop的表闪回,并重名名为t2:

flashback table "BIN$01795tP0Z7/gU9MKqMC7QA==$0" to before drop rename to t2;

Oracle闪回技术详解及应用_第20张图片

 此时我们看到表已经恢复了,并且命名为t2。

如果要在drop表时永久性删除,可以附加purge子句,此时表不会进回收站,而是彻底从数据库删除(效果相当于windows下shift+delete)。如果要恢复只能采用其他方法了。

七、闪回数据库(Flashback Database)

闪回数据库是利用闪回日志撤销近期的变更,将数据库回退到近期的一个时间点。在效果上和时间点恢复(Point-In-Time Recovery)类似,但是闪回数据库不需要还原数据文件和应用redo日志,因此速度快很多。

闪回数据库用的是一套独立的日志系统。闪回日志存储在快速恢复区(Fast Recovery Area,FRA)中,所以开启闪回前要确保FRA配置好,否则无法生成闪回日志。

配置闪回数据库:

1. 首先确定数据库处于归档模式且FRA已经配置:

archive log list;  -- 查看归档状态。

show parameter db_recovery_file_dest  -- 查看FRA是否配置,因为flashback logs无法存在FRA之外的地方,建议打开闪回数据库后将FRA配置大一点。

Oracle闪回技术详解及应用_第21张图片

 2. 打开闪回日志:

确保数据库处于mount或open状态下,打开数据库闪回。

alter database flashback on;  -- 开启闪回日志

select flashback_on from v$database;  -- 查询v$database.flashback_on查看是否已开启闪回

Oracle闪回技术详解及应用_第22张图片

 3. 根据需求调整闪回窗口时长:

参数db_flashback_retention_target定义了闪回日志保存的目标时长(默认是1440分钟,一天),数据库可以闪回至窗口内的任意时间点。

show parameter flashback

Oracle闪回技术详解及应用_第23张图片

配置完成后,数据库就已经开始记录闪回日志了。

闪回至SCN示例:

数据库的闪回目标可以是SCN,时间点,日志序列号或还原点(restore_point)。

闪回至SCN:

1. 首先可以通过v$flashback_database_log查询闪回窗口的最小SCN和时间点,再往前的时间点将无法闪回:

select oldest_flashback_scn, oldest_flashback_time from v$flashback_database_log;

Oracle闪回技术详解及应用_第24张图片

2. 重启数据库至mount状态,使用flashback database to scn,将数据库闪回至指定SCN:

shutdown immediate;

startup mount;

flashback database to scn 1792364;

Oracle闪回技术详解及应用_第25张图片

 3. 使用open resetlogs选项打开数据库:

闪回数据库必须使用open resetlogs打开,此选项会创建一个新的数据库化身(incarnation)。

alter database open resetlogs;

闪回至还原点(restore point)示例:

1. 创建还原点:

假设我们需要对数据库进行重大变更,希望失败后可以还原至原始状态,可以在操作前创建一个还原点。

create restore point before_update guarantee flashback database;

guarantee flashback database子句代表创建的是一个guaranteed restore point,如果不加这个子句则创建的是normal restore point。两者不同是normal restore point会随着时间自动删除,而guaranteed restore point必须显式手动删除。数据库将一直保存guaranteed restore point之后产生的闪回日志,即使超过flashback window或关闭闪回日志都不行。数据库将确保能够闪回至这个时间点。所以如果FRA过小或忘记删除,guaranteed restore point可能会导致FRA空间耗尽,数据库挂起。

 在RMAN中可以查看我们创建的还原点:

list restore point all;

Oracle闪回技术详解及应用_第26张图片

2. 重启数据库至mount状态,使用flashback database to restore point,将数据库闪回至指定还原点:

shutdown immediate;

startup mount;

Oracle闪回技术详解及应用_第27张图片

flashback database to restore point before_update;

 3. 使用open resetlogs选项打开数据库:

alter database open resetlogs;

 使用open resetlogs选项打开数据库后将创建一个新的incarnation,相关的信息可以从v$database_incarnation中查询:

select * from v$database_incarnation;

Oracle闪回技术详解及应用_第28张图片

使用闪回数据库撤销上一次resetlogs:

闪回数据库可以跨越incarnation,因此也可以用闪回数据库来撤销open resetlogs影响:

1. 首先确定数据库open resetlogs的SCN在闪回窗口内:

select resetlogs_change# from v$database; 

select oldest_flashback_scn from v$flashback_database_log;

可以看到v$database.resetlogs_change#的值大于v$flashback_database_log.oldest_flashback_scn。则说明可以用flashback database 撤销resetlogs。

Oracle闪回技术详解及应用_第29张图片

2. 重启数据库至mount状态,撤销resetlogs:

shutdown immediate;

startup mount;

flashback database to before resetlogs; -- 数据库将会被闪回至紧靠resetlogs之前的SCN。

Oracle闪回技术详解及应用_第30张图片

 3. 再次使用open resetlogs打开数据库,上一次open resetlogs之后的所有变更已被撤销。

4.从v$database_incarnation中,我们看到incarnation#为4,5的父级incarnation#都是3。5的status是current(当前),4的status是orphan(孤儿),代表上一次resetlogs已成功撤销。

Oracle闪回技术详解及应用_第31张图片

闪回数据库是利用闪回日志撤销变更,从当前时间点向后退。而备份恢复是将数据库还原至历史备份时间点,然后应用redo日志重放数据库变更(两种技术的还原方向不同)。因此闪回的速度只受变更数据量大小影响。而备份恢复因为要还原整库,受整个数据库大小的影响。虽然2种技术都可以将数据库还原至指定时间点,但闪回数据库具有明显的速度优势。且在不确定闪回是否满足需求时,在open resetlogs之前可以先用open readonly选项打开数据库查看,多次闪回以试探正确的还原时间点。

你可能感兴趣的:(Oracle,oracle,数据库,database)