介绍
虽然我们可以使用闪回查询来查询事务提交之前的历史数据,但这种查询经常需要执行多次才能获得想要的结果。例如,在某个时间间隔内误运行了某个事务(事务已提交),后面我们发现脚本执行错了,想要查询出事务牵扯到的表中修改前的数据,去跟现在表中的数据进行对比,来知道执行事务前的时间。假设我们使用闪回查询去找的话,首先就需要随便查一个你认为可能会包含事务提交前的历史数据的时间点。如果这个时间正好是事务执行前的时间,那你就可以直接闪回表结束这个事情,还不会有任何责任,但这种可能性太低了。如果这个时间没有查到,就只能将时间改的更早些,然后反复修改和查询,直至找到事务执行前的时间。在这个反复查询的过程中,你需要修改多少次时间?要知道,对于数据库来说,1秒内就可能会执行多个事务,难道修改时间要精确到毫秒位?如果按毫秒位,又需要改多少次呢?那么,有没有一种方法能查询到一段时间间隔内的事务变更情况呢?
答案是有,它就是Flashback Version Query。
Oracle在每次事务执行时,就会将事务涉及到的旧值给移动到UNDO表空间中,待事务提交(commit)后,表中的行数据就会确定新的值,这种新值和旧值切换的过程,就是一个行的版本。当然,实际上的事务操作会更复杂,我只是为了让你们理解行版本,简述了下事务和UNDO表空间的关系。从这里可以看到,Flashback Version Query同样是使用了UNDO的特性,才能够让我们查询到一定时间段内行数据的版本。
Flashback Version Query提供了6个伪列,通过这些伪列,能够让我们查询到行版本的创建时间、过期时间、事务标识符和事务执行的操作类型。以下为伪列的说明:
伪列 | 描述 | 备注 |
VERSIONS_STARTSCN | 创建行版本时的数据库变更号(SCN) | 此值为NULL,则行版本是在之前创建的 |
VERSIONS_STARTTIME | 创建行版本时的时间戳(TIMESTAMP) | 此值为NULL,则行版本是在之前创建的 |
VERSIONS_ENDSCN | 行版本过期时的数据库变更号(SCN) | 此值为NULL,则行版本当前的,或者行数据执行了删除操作 |
VERSIONS_ENDTIME | 行版本过期时的时间戳(TIMESTAMP) | 此值为NULL,则行版本当前的,或者行数据执行了删除操作 |
VERSIONS_XID | 创建行版本时的事务标识符 | |
VERSIONS_OPERATION | 事务对行中的数据进行的操作。I-插入;D-删除;U-更新 | 对于更新索引键时,Flashback Version Query将update操作视为DELETE+INSERT。 |
语法
闪回版本查询的语法非常简单,它结合了BETWEEN...AND子句。语法如下所示:
VERSIONS {BETWEEN {SCN | TIMESTAMP} start AND end}
说明:
- SCN 使用SCN(数据库变更号)
- TIMESTAMP 使用TIMESTAMP(时间戳)
- start SCN或TIMESTAMP的开始值
- end SCN或时间戳的结束值
先决条件
在执行闪回版本查询前,必须要满足以下条件:
- 当前用户必须在执行闪回查询的表中具有FLASHBACK权限或者具有FLASHBACK ANY TABLE系统权限。
- 当前用户必须在执行闪回查询的表中具有SELECT权限。
案例
TIMESTAMP闪回版本查询
还是这样一张表testa,数据如下图所示:
在进行表维护时,误执行了update语句,将表中NAME字段的全部数据改成了“赵六”。脚本如下图所示:
此时我们想使用闪回版本查询,查询在某个时间段内的行变更记录,可以这样写:
select
versions_startscn, versions_starttime,
versions_endscn, versions_endtime,
versions_xid, versions_operation,
id,name,sex
from testa
versions between timestamp
to_timestamp('2021-12-29 18:20:00','yyyy-mm-dd hh24:mi:ss')
and to_timestamp('2021-12-29 18:23:00','yyyy-mm-dd hh24:mi:ss');
从上图可以看到,testa表有两行被执行了更新,更新时间是“2021-12-29 18:21:03”。我这里是为了让你们更好的理解这些伪列的使用,所以在查询时全部都查出来了。在生产环境中,建议根据条件去写闪回版本查询语句,避免因行版本数据量太多导致的性能问题。
我这里再写一个用ID字段作为条件去查询“ID=1”的闪回版本查询的语句。
select
versions_startscn, versions_starttime,
versions_endscn, versions_endtime,
versions_xid, versions_operation,
id,name,sex
from testa
versions between timestamp
to_timestamp('2021-12-29 18:20:00','yyyy-mm-dd hh24:mi:ss')
and to_timestamp('2021-12-29 18:23:00','yyyy-mm-dd hh24:mi:ss')
where id=1;
评论区