当用户操作不慎导致误删改数据时,闪回技术可以简单快捷地恢复数据。
该技术主要是通过回滚段存储的 UNDO 记录来完成历史记录的还原。设置ENABLE_FLASHBACK 为 1 后,开启闪回功能。DM 会保留回滚段一段时间,回滚段保留的时间代表着可以闪回的时间长度。由 UNDO_RETENTION 参数指定。
下面开始我们的发现之旅。
1、参数设置
设置闪回参数
sp_set_para_value(1,'ENABLE_FLASHBACK',1);设置回滚段可以保留的时间长度
sp_set_para_double_value(1,'UNDO_RETENTION',10800);2、测试准备
2.1创建测试表并加载数据,执行检查点
create table test(id int,num int);
insert into test select level,level from dual connect by level <=100000;
commit;
checkpoint(100);2.2打开几个会话分别收集如下统计信息
####会话1 收集BUFFERPOOL使用情况
select sum(n_pages),sum(n_phy_write) ,sum(n_dirty)
from v$bufferpool
where name='NORMAL';
行号 SUM(N_PAGES) SUM(N_PHY_WRITE) SUM(N_DIRTY)
---------- -------------------- -------------------- --------------------
1 508997 1719 0
####会话2 收集回滚段信息
SQL> select * from V$PURGE;
行号 OBJ_NUM IS_RUNNING PURG_FOR_TS
---------- ----------- ---------- -----------
1 1 Y N
SQL> select TRX_ID,TAB_ID,ROW_COUNT from V$PURGE_PSEG_TAB;
行号 TRX_ID TAB_ID ROW_COUNT
---------- -------------------- ----------- --------------------
1 91766 1075 100000
SQL> select nth,n_pages,n_extend,n_used_pages,reserve_time
2 from V$PSEG_ITEMS order by 2 desc limit 1;
行号 NTH N_PAGES N_EXTEND N_USED_PAGES RESERVE_TIME
---------- ----------- ----------- ----------- ------------ ------------
1 0 256 0 0 10800
####会话3 回滚表空间信息
SQL> select
2 (select bytes/1024/1024.0 from dba_data_files where tablespace_name='ROLL')
3 -
4 (select bytes/1024/1024.0 from dba_free_space where tablespace_name='ROLL')
5 UNDO_TABLESPACE_USED_M
6 /
行号 UNDO_TABLESPACE_USED_M
---------- ----------------------
1 10.734375
####会话4 闪回版本查询
SQL> SELECT VERSIONS_STARTTRXID,VERSIONS_ENDTRXID, VERSIONS_OPERATION ,id,num
2 FROM test VERSIONS BETWEEN TIMESTAMP sysdate-1.0/24 AND SYSDATE
3 where id=1
4 /
行号 VERSIONS_STARTTRXID VERSIONS_ENDTRXID VERSIONS_OPERATION ID NUM
---------- -------------------- -------------------- ------------------ ----------- -----------
1 91766 NULL I 1 13、数据更新
3.1更新数据,执行检查点
update test set num=num+1;
commit;
checkpoint(100);3.2执行查询统计
2.2中的4个会话SQL。
3.3重复执行
执行3.1和3.2
4、查询闪回数据
4.1显示闪回多版本:

行号 VERSIONS_STARTTRXID VERSIONS_ENDTRXID VERSIONS_OPERATION ID NUM
---------- -------------------- -------------------- ------------------ ----------- -----------
1 91772 NULL U 1 3
2 91767 91772 U 1 2
3 91766 91767 I 1 1
已用时间: 407.825(毫秒). 执行号:902.可以看出存在三个数据版本。91766事务完成INSERT操作,NUM字段为1。91767事务完成UPDATE操作,NUM字段被更新为2。91772事务完成UPDATE操作,NUM字段被更新为3。
4.2根据闪回事务号查询SQL历史执行情况:

SET LINESHOW OFF
select trx_id,sql_id,seq_no,substr(top_sql_text,1,30) sql,start_time,affected_rows
from v$sql_history where trx_id in (91766,91767,91772)order by seq_no;
91766 16 20 insert into test select level, 2023-01-15 16:23:14.000000 100000
91767 17 21 checkpoint(100) 2023-01-15 16:23:18.000000 0
91767 25 30 update test set num=num+1; 2023-01-15 16:32:51.000000 100000
TRX_ID SQL_ID SEQ_NO SQL START_TIME AFFECTED_ROWS
-------------------- ----------- ----------- -------------------------- -------------------------- -------------
91767 26 31 commit; 2023-01-15 16:32:51.000000 0
91772 27 32 checkpoint(100); 2023-01-15 16:32:51.000000 0
91772 25 39 update test set num=num+1; 2023-01-15 16:37:03.000000 100000
91772 26 40 commit; 2023-01-15 16:37:03.000000 0查询出的结果与执行顺序一致
4.3根据SQL历史执行情况中的时间查询闪回数据

SQL> select * from(select * from test WHEN TIMESTAMP '2023-01-15 16:32:51' ) where id=1;
ID NUM
----------- -----------
1 1
已用时间: 141.382(毫秒). 执行号:916.
SQL> select * from(select * from test WHEN TIMESTAMP ' 2023-01-15 16:37:03' ) where id=1;
ID NUM
----------- -----------
1 2
已用时间: 90.876(毫秒). 执行号:917.
SQL> select * from test where id=1;
ID NUM
----------- -----------
1 3
已用时间: 9.606(毫秒). 执行号:918.查询出的结果与变更顺序一致
注:sql执行时间也可以通过V$PSEG_COMMIT_TRX 视图查询。
如果知道修改时间,可以跳过4.1和4.2直接根据时间查询闪回数据。
5、后台视图分析
5.1回滚段查看

SQL> select * from V$PURGE;
行号 OBJ_NUM IS_RUNNING PURG_FOR_TS
---------- ----------- ---------- -----------
1 3 Y N
已用时间: 0.437(毫秒). 执行号:706.
SQL> select TRX_ID,TAB_ID,ROW_COUNT from V$PURGE_PSEG_TAB;
行号 TRX_ID TAB_ID ROW_COUNT
---------- -------------------- ----------- --------------------
1 91772 1075 0
2 91767 1075 0
3 91766 1075 100000
已用时间: 0.354(毫秒). 执行号:707.
SQL> select nth,n_pages,n_extend,n_used_pages,reserve_time
2 from V$PSEG_ITEMS order by 2 desc limit 1;
行号 NTH N_PAGES N_EXTEND N_USED_PAGES RESERVE_TIME
---------- ----------- ----------- ----------- ------------ ------------
1 1 1440 74 1430 10800
已用时间: 0.336(毫秒). 执行号:708.查询V$PURGE视图显示共有3个待 PURGE 事务。等到10800秒(UNDO_RETENTION)后查询该视图结果为空。
查询V$PURGE_PSEG_TAB 视图显示有三个会话待 PURGE ,分别为91766、91767和91772,均对应着id等于1075的对象,即test表。
查询V$PSEG_ITEMS视图显示回滚段保留时间为10800(RESERVE_TIME)秒,两个回滚段共占据1430个PAGE,每个715PAGE。
注:INSERT操作没有前数据,不占用回滚空间。
5.2查看BUFFER池情况

select sum(n_pages),sum(n_phy_write) ,sum(n_dirty)
from v$bufferpool
where name='NORMAL';
行号 SUM(N_PAGES) SUM(N_PHY_WRITE) SUM(N_DIRTY)
---------- -------------------- -------------------- --------------------
1 508997 1719 0
已用时间: 0.230(毫秒). 执行号:601.
SQL> /
行号 SUM(N_PAGES) SUM(N_PHY_WRITE) SUM(N_DIRTY)
---------- -------------------- -------------------- --------------------
1 508997 2842 0
已用时间: 0.363(毫秒). 执行号:602.
SQL> /
行号 SUM(N_PAGES) SUM(N_PHY_WRITE) SUM(N_DIRTY)
---------- -------------------- -------------------- --------------------
1 508997 3967 0
已用时间: 0.423(毫秒). 执行号:603.N_PHY_WRITE为实例开机以来系统缓冲区累计物理写的次(页)数。由上可见,每次均比前值多大约1124个页面。
查询test表大小

SQL> select bytes/page from dba_segments where segment_name='TEST';
BYTES/PAGE
--------------------
432
已用时间: 120.798(毫秒). 执行号:903.从上面得知本次测试回滚段715个页面。432+715=1147,去除控制块等内部结构,基本等于上面的1124。
注:回滚段保存修改前的数据。本测试是全表更新,所以理应大小与表相等。但实际测试大很多。分析原因是回滚段中除了保存完整的修改前数据以外,还需要保存数据的逻辑地址和版本号、事务号以及修改时间,以支持闪回查询。
每次commit后执行检查点(checkpoint(100))会将BUFFER池中表数据和回滚段数据一起写入磁盘。表示数据写入用户表空间。回滚段数据写入ROLL表空间。
5.3查看回滚表空间使用情况

SQL> select
2 (select bytes/1024/1024.0 from dba_data_files where tablespace_name='ROLL')
3 -
4 (select bytes/1024/1024.0 from dba_free_space where tablespace_name='ROLL')
5 UNDO_TABLESPACE_USED_M
6 /
行号 UNDO_TABLESPACE_USED_M
---------- ----------------------
1 10.734375
已用时间: 5.434(毫秒). 执行号:801.
SQL> /
行号 UNDO_TABLESPACE_USED_M
---------- ----------------------
1 14.359375
已用时间: 6.899(毫秒). 执行号:802.
SQL> /
行号 UNDO_TABLESPACE_USED_M
---------- ----------------------
1 19.984375
已用时间: 6.395(毫秒). 执行号:803.由上可见,ROLL表空间一直在增长。
6、结论
可以通过“select * from 表名 WHEN TIMESTAMP ' 时间'”查询过去某一个时点的数据。如果时间点不明确,可以查询V$PURGE_PSEG_TAB视图查看曾经修改某表的事务号,再通V$PSEG_COMMIT_TRX视图或者V$SQL_HISTORY视图查询事务提交时间。
设置ENABLE_FLASHBACK 为 1 后,才能使用闪回查询。ENABLE_FLASHBACK 等于 0时系统照样会保存回滚段信息, V$PURGE、V$PURGE_PSEG_TAB、V$PSEG_COMMIT_TRX、V$PSEG_ITEMS 等视图有效。以上视图数据保留由UNDO_RETENTION 参数决定。
select name,sum(n_pages),sum(n_phy_write) ,sum(n_dirty)
from v$bufferpool
where name='NORMAL' or name='ROLL'
group by name
行号 NAME SUM(N_PAGES) SUM(N_PHY_WRITE) SUM(N_DIRTY)
---------- ------ ------------ -------------------- --------------------
1 NORMAL 508997 3967 0
2 ROLL 128 0 0回滚段数据的物理存储空间是ROLL表空间,但对应的内存空间是BUFFER缓冲区,不是ROLL缓冲区。这一点没有找到官方文档中相应解释。
















