Oracle误操作先别慌:Flashback、UNDO、回收站、Redo 与归档日志一次讲清楚 2026-05-24
1、背景说明
本文整理 Oracle 生产环境中误操作恢复相关的核心知识点,包括:
Flashback Database Flashback Query UNDO Recycle Bin FRA 快速恢复区 Redo Archived Redo Log 归档日志适用于 Oracle 单实例、RAC,以及 CDB/PDB 多租户环境。
在 CDB/PDB 环境中要特别注意执行层级:
【CDB$ROOT 执行】 看数据库级配置、FRA、Redo、归档、全局状态 【业务 PDB 执行】 看具体业务表、回收站对象、Flashback Query 数据恢复 【谨慎执行】 涉及恢复、变更、清理动作,生产环境必须走变更流程一句话:
数据库级能力看 CDB$ROOT; 业务对象恢复进业务 PDB。2、不同误操作对应的恢复路线
| 误操作类型 | 优先恢复方向 | 核心依赖 |
|---|---|---|
DELETE | Flashback Query | UNDO |
UPDATE | Flashback Query | UNDO |
DROP TABLE | Recycle Bin | 回收站 |
TRUNCATE TABLE | RMAN / 归档 / 备库 | 备份恢复能力 |
| 整库误操作 | Flashback Database / RMAN | Flashback Log / 备份归档 |
简单记:
DELETE / UPDATE 看 UNDO; DROP TABLE 看回收站; TRUNCATE 看备份; 整库回退看 Flashback Database 或 RMAN。3、先确认当前所在容器
【当前会话执行】
show con_name;查看当前有哪些 PDB:
【CDB$ROOT 执行】
show pdbs;切换到具体业务 PDB:
【业务 PDB 执行前】
alter session set container=业务PDB名称; show con_name;切回 CDB$ROOT:
alter session set container=CDB$ROOT;4、查看数据库级 Flashback Database 是否开启?
数据库级闪回,也就是Flashback Database,用于将整个数据库回退到某个时间点或 SCN。
【CDB$ROOT 执行】
select name, open_mode, database_role, log_mode, flashback_on from v$database;重点看:
FLASHBACK_ON常见结果:
| FLASHBACK_ON | 含义 |
|---|---|
YES | 已开启数据库级 Flashback Database |
NO | 未开启数据库级 Flashback Database |
RESTORE POINT ONLY | 仅支持保证还原点相关闪回 |
如果结果是:
FLASHBACK_ON = NO说明当前没有开启数据库级闪回,不能直接做整库级回退:
flashback database to timestamp ...; flashback database to scn ...;注意:数据库级 Flashback Database 没开启,不影响 Flashback Query 查询几分钟前的数据。
Flashback Query 依赖的是UNDO,不是 Flashback Log。
5、FRA 快速恢复区是什么?
FRA,全称 Fast Recovery Area,也叫快速恢复区,主要用于存放:
归档日志 闪回日志 控制文件自动备份 RMAN 备份片 镜像副本 恢复相关文件查看 FRA 配置:
【CDB$ROOT 执行】
show parameter db_recovery_file_dest; show parameter db_recovery_file_dest_size;示例:
db_recovery_file_dest = +RECO db_recovery_file_dest_size = 2000G说明 FRA 已配置在指定位置,大小上限为 2000G。
但注意:FRA 配置了,不等于数据库级闪回已经开启。
最终是否开启 Flashback Database,还是看:
select flashback_on from v$database;6、FRA 配置了但没开启闪回,是不是白配置?
不是。
FRA 不是只给 Flashback Database 用,它还可以用于归档日志、RMAN 备份片、控制文件自动备份等恢复相关文件。
另外:
db_recovery_file_dest_size = 2000G只是 Oracle 允许 FRA 使用的上限,不代表已经实际占用了 2000G。
查看 FRA 实际使用情况:
【CDB$ROOT 执行】
set linesize 200 col name for a40 select name, round(space_limit / 1024 / 1024 / 1024, 2) as limit_gb, round(space_used / 1024 / 1024 / 1024, 2) as used_gb, round(space_reclaimable / 1024 / 1024 / 1024, 2) as reclaimable_gb, number_of_files from v$recovery_file_dest;结论:
FRA 不是白配置; 没开启 Flashback Database,只是没有使用 Flashback Log 这部分能力。7、查看 FRA 各类文件占用
【CDB$ROOT 执行】
set linesize 200 col file_type for a25 select file_type, percent_space_used, percent_space_reclaimable, number_of_files from v$recovery_area_usage order by percent_space_used desc;重点关注:
ARCHIVED LOG BACKUP PIECE FLASHBACK LOG如果:
FLASHBACK LOG = 0 FLASHBACK_ON = NO说明当前没有开启数据库级 Flashback Database,也没有产生 Flashback Log。
8、查看是否存在 Restore Point
Restore Point 是还原点,尤其是 Guaranteed Restore Point,可能会强制保留闪回相关日志,占用 FRA 空间。
【CDB$ROOT 执行】
set linesize 200 col name for a30 col time for a35 col guarantee_flashback_database for a10 select name, scn, time, guarantee_flashback_database, round(storage_size / 1024 / 1024 / 1024, 2) as storage_gb from v$restore_point order by time desc;如果结果为:
no rows selected说明当前没有普通还原点,也没有保证还原点。
如果存在:
GUARANTEE_FLASHBACK_DATABASE = YES要重点关注,保证还原点可能长期占用 FRA 空间。
9、数据库级闪回没开启,还能查几分钟前误删数据吗?
可以。
要区分两个概念:
| 能力 | 作用 | 依赖 |
|---|---|---|
| Flashback Database | 整库级回退 | Flashback Log |
| Flashback Query | 查询历史版本数据 | UNDO |
如果是:
delete from 表名 where 条件; commit;或者:
update 表名 set 字段 = 值 where 条件; commit;可以尝试通过 Flashback Query 查询历史版本。
10、如何查询几分钟前被误删的数据?
如果是 CDB/PDB 环境,先切到表所在的业务 PDB。
【业务 PDB 执行】
alter session set container=业务PDB名称; show con_name;查询当前时间:
select systimestamp from dual;查询 5 分钟前的数据:
select * from Schema名.表名 as of timestamp systimestamp - interval '5' minute where 条件;示例:
select * from Schema名.业务表 as of timestamp systimestamp - interval '5' minute where 主键字段 = 主键值;这里的Schema名指的是该 PDB 下对象所属的 schema,也就是表的 owner。
查找“当前没有、5 分钟前存在”的数据:
【业务 PDB 执行】
select * from Schema名.表名 as of timestamp systimestamp - interval '5' minute old where not exists ( select 1 from Schema名.表名 now where now.主键字段 = old.主键字段 );生产环境建议先落备份表,不要直接插回原表:
【业务 PDB 执行,谨慎执行】
create table Schema名.表名_flashback_bak_20260522 as select * from Schema名.表名 as of timestamp systimestamp - interval '5' minute where 条件;确认数据无误后再恢复:
【业务 PDB 执行,谨慎执行】
insert into Schema名.表名 select * from Schema名.表名_flashback_bak_20260522; commit;如果确认不会主键冲突,也可以直接从历史版本插回:
【业务 PDB 执行,谨慎执行】
insert into Schema名.表名 select * from Schema名.表名 as of timestamp systimestamp - interval '5' minute old where not exists ( select 1 from Schema名.表名 now where now.主键字段 = old.主键字段 ); commit;11、如何确认表属于哪个 Schema?
在对应业务 PDB 中执行:
【业务 PDB 执行】
select owner, object_name, object_type, status from dba_objects where object_name = upper('表名') order by owner, object_type;如果结果是:
OWNER OBJECT_NAME OBJECT_TYPE ---------- --------------- ----------- ECOLOGY TEST_TABLE TABLE那么完整表名就是:
ECOLOGY.TEST_TABLE在 Oracle 中可以简单理解:
User ≈ Schema文章中统一使用Schema名,避免和操作系统用户名混淆。
12、UNDO 保留时间如何查看?
UNDO 保留时间影响 Flashback Query 能查多久。
【CDB$ROOT 执行,RAC 环境建议用 GV$ 视图】
select inst_id, name, value, round(to_number(value)/60,2) as minutes from gv$parameter where name = 'undo_retention' order by inst_id;示例:
undo_retention = 900 秒 = 15 分钟含义是:Oracle 目标上尽量保留最近 15 分钟内的旧版本数据。
但注意:
UNDO_RETENTION 是目标值,不是绝对保证。如果 UNDO 空间不足、DML 压力过大,旧版本数据仍可能提前被覆盖。
13、UNDO 空间和 Flashback Query 的关系
Flashback Query 能查多久,主要取决于:
UNDO_RETENTION 设置 UNDO 表空间大小 UNDO 是否被覆盖 业务 DML 压力 UNDO 表空间是否 GUARANTEE查看是否启用 Local Undo:
【CDB$ROOT 执行】
select property_name, property_value from database_properties where property_name = 'LOCAL_UNDO_ENABLED';如果结果是:
LOCAL_UNDO_ENABLED = TRUE说明在 CDB/PDB 环境中,每个 PDB 可以拥有自己的本地 UNDO。
查看各 PDB 的 UNDO 表空间:
【CDB$ROOT 执行】
set linesize 200 col pdb_name for a20 col tablespace_name for a25 col retention for a15 select c.name as pdb_name, t.con_id, t.tablespace_name, t.contents, t.retention from cdb_tablespaces t join v$containers c on t.con_id = c.con_id where t.contents = 'UNDO' order by t.con_id, t.tablespace_name;重点看:
RETENTION如果:
RETENTION = NOGUARANTEE说明不强制保证 UNDO 保留时间。空间紧张时,Oracle 可以提前复用未过期 UNDO。
如果:
RETENTION = GUARANTEE说明尽量强制保证 UNDO 保留时间,但空间不足时可能导致业务 DML 报错,生产环境要慎用。
14、查看 UNDO 文件大小和实际占用
这一步建议在CDB$ROOT层级查就可以,总览所有 PDB 的 UNDO,看 CDB$ROOT;精查某个 PDB,再切业务 PDB。
CDB$ROOT 执行: 在 CDB/PDB 环境中,建议直接在 CDB$ROOT 下通过 CDB_DATA_FILES、CDB_TABLESPACES 、CDB_UNDO_EXTENTS 等 CDB_* 视图总览所有 PDB 的 UNDO 文件大小和实际占用情况。 如果只想查看某一个业务 PDB,也可以切换到对应 PDB 后使用 DBA_TABLESPACES、 DBA_DATA_FILES 等 DBA_* 视图单独查询。查看 UNDO 文件大小和是否自动扩展:
【CDB$ROOT 执行】
set linesize 260 set pagesize 100 col pdb_name for a20 col tablespace_name for a25 col file_name for a90 col autoextensible for a15 select c.name as pdb_name, d.con_id, d.tablespace_name, round(d.bytes / 1024 / 1024 / 1024, 2) as size_gb, d.autoextensible, round(d.maxbytes / 1024 / 1024 / 1024, 2) as max_gb, d.file_name from cdb_data_files d join cdb_tablespaces t on d.con_id = t.con_id and d.tablespace_name = t.tablespace_name join v$containers c on d.con_id = c.con_id where t.contents = 'UNDO' order by d.con_id, d.tablespace_name, d.file_name;查看 UNDO 实际占用状态:
【CDB$ROOT 执行】
set linesize 200 set pagesize 100 col pdb_name for a20 col tablespace_name for a25 col status for a15 select c.name as pdb_name, u.con_id, u.tablespace_name, u.status, round(sum(u.bytes) / 1024 / 1024, 2) as mb from cdb_undo_extents u join v$containers c on u.con_id = c.con_id group by c.name, u.con_id, u.tablespace_name, u.status order by u.con_id, u.tablespace_name, u.status;状态说明:
| STATUS | 含义 |
|---|---|
ACTIVE | 正在被事务使用,不能复用 |
UNEXPIRED | 事务已提交,但仍在保留期内 |
EXPIRED | 已过保留期,可以复用 |
判断逻辑:
ACTIVE 高:可能有大事务或长事务 UNEXPIRED 高:旧版本仍在保留期内 EXPIRED 高:看似占用,但需要时可以复用15、什么时候应该扩容 UNDO?
不要只看 UNDO 文件大不大,要看有没有真正撑不住。
应该考虑扩容的典型信号:
出现 ORA-30036:UNDO 表空间无法扩展 出现 ORA-01555:snapshot too old gv$undostat.nospaceerrcnt > 0 gv$undostat.ssolderrcnt > 0 ACTIVE 持续很高 UNDO 文件接近 MAXSIZE 且无法继续扩展 业务要求更长时间的 Flashback Query查询 UNDO 历史状态:
【CDB$ROOT 执行,RAC 环境建议用 GV$ 视图】
set linesize 220 set pagesize 100 col begin_time for a20 col end_time for a20 select inst_id, to_char(begin_time,'yyyy-mm-dd hh24:mi') as begin_time, to_char(end_time,'yyyy-mm-dd hh24:mi') as end_time, undoblks, txncount, maxquerylen, tuned_undoretention, round(tuned_undoretention/60,2) as tuned_minutes, ssolderrcnt, nospaceerrcnt from gv$undostat order by inst_id, begin_time desc fetch first 40 rows only;字段说明:
| 字段 | 含义 |
|---|---|
SSOLDERRCNT | ORA-01555 次数 |
NOSPACEERRCNT | UNDO 空间不足次数 |
TUNED_UNDORETENTION | Oracle 实际调优后的 UNDO 保留时间 |
MAXQUERYLEN | 最长查询时间 |
判断口诀:
ORA-30036 要扩容; ORA-01555 要评估; ACTIVE 高要排查; NOSPACEERRCNT 大概率要扩; SSOLDERRCNT 说明旧版本保留不住; 文件大但 ACTIVE 低,不急着动。16、ORA-01555 一定会写入 alert 日志吗?
不一定。
ORA-01555: snapshot too old通常是业务 SQL 或用户会话执行查询时报错,优先出现在:
应用日志 SQL 客户端报错 会话 trace gv$undostat / dba_hist_undostat 统计Alert 日志中可能出现,但不保证一定出现。
所以判断是否发生过 ORA-01555,优先看:
【CDB$ROOT 执行】
select inst_id, begin_time, end_time, ssolderrcnt, nospaceerrcnt from gv$undostat order by begin_time desc;如果要查历史趋势,可结合 AWR:
【CDB$ROOT 执行】
select instance_number, begin_time, end_time, ssolderrcnt, nospaceerrcnt from dba_hist_undostat where begin_time >= sysdate - 7 order by begin_time desc, instance_number;17、Recycle Bin 回收站是什么?
Recycle Bin 是 Oracle 的“DROP 表后悔药”。
如果执行:
drop table 表名;并且没有加purge,表通常不会立刻物理删除,而是进入回收站,名字变成类似:
BIN$xxxxxx==$0后续可以尝试恢复:
flashback table Schema名.表名 to before drop;查询回收站是否开启:
【CDB$ROOT 和业务 PDB 都建议查,重点看业务 PDB】
show parameter recyclebin;如果结果为:
recyclebin = onon说明回收站已开启。
建议在业务 PDB 中再确认一次:
【业务 PDB 执行】
alter session set container=业务PDB名称; show parameter recyclebin;18、回收站能找回什么?不能找回什么?
| 操作 | 回收站能否恢复 | 说明 |
|---|---|---|
DROP TABLE | 可以尝试 | 前提是没 purge,且对象还在回收站 |
DROP TABLE ... PURGE | 不能 | 直接绕过回收站 |
DELETE | 不能靠回收站 | 要靠 UNDO / Flashback Query |
TRUNCATE | 不能靠回收站 | 通常靠备份、归档、备库 |
DROP USER ... CASCADE | 风险很高 | 不能按普通回收站思路处理 |
简单记:
DELETE 看 UNDO; DROP 看 Recycle Bin; TRUNCATE 看备份。19、如何查回收站里有没有误删表?
必须进入表所在的业务 PDB 查询。
【业务 PDB 执行】
alter session set container=业务PDB名称; show con_name;查看最近 DROP 的对象:
【业务 PDB 执行】
set linesize 200 col owner for a20 col original_name for a30 col object_name for a50 col type for a20 col droptime for a25 select owner, original_name, object_name, type, ts_name, droptime, can_undrop, can_purge from dba_recyclebin order by droptime desc fetch first 30 rows only;如果知道表名:
【业务 PDB 执行】
select owner, original_name, object_name, type, ts_name, droptime, can_undrop, can_purge from dba_recyclebin where original_name = upper('表名') order by droptime desc;恢复原表名:
【业务 PDB 执行,谨慎执行】
flashback table Schema名.表名 to before drop;如果原表名已经被重新创建,可以恢复成新名字:
【业务 PDB 执行,谨慎执行】
flashback table Schema名.表名 to before drop rename to 表名_recover;20、Recycle Bin 保留多长时间?
Recycle Bin没有固定保留时间。
它不像:
undo_retention = 900 秒 db_flashback_retention_target = 1440 分钟Recycle Bin 不是按时间保留,而是按空间和清理动作决定。
只要满足下面条件,它可能保留很久:
没人手动 purge 不是 drop table ... purge 表空间空间充足 用户 quota 充足 Oracle 没有因为空间压力自动回收但如果空间紧张,Oracle 可能自动清理回收站对象释放空间。
所以准确说:
没人手动清理,不等于永久保留; 空间充足时可能长期保留; 空间紧张时可能自动回收。一句话:回收站是临时仓库,不是保险柜。
21、UNDO 和 REDO 的区别
最核心区别:
UNDO:负责后悔 REDO:负责重来| 类型 | 作用 |
|---|---|
| UNDO | 回滚事务、读一致性、Flashback Query |
| REDO | 实例恢复、介质恢复、归档恢复、Data Guard |
常见操作:
| 操作 | UNDO | REDO |
|---|---|---|
INSERT | 有 | 有 |
UPDATE | 有 | 有 |
DELETE | 有 | 有 |
MERGE | 有 | 有 |
SELECT | 一般不产生,但可能读取 UNDO | 一般不产生 |
CREATE TABLE | 少量数据字典 UNDO | 有 |
DROP TABLE | 少量数据字典 UNDO | 有 |
TRUNCATE | 少量元数据 UNDO | 有 |
CREATE INDEX | 视情况 | 有,nologging 可减少部分 redo |
注意:UNDO 本身的变化也会产生 REDO。
例如一次UPDATE:
修改前的数据写入 UNDO; 修改后的变化产生 REDO; UNDO 块本身的变化也会产生 REDO; COMMIT 时 LGWR 确保 redo 写入 online redo log。22、Redo 什么时候开始循环使用?
Redo 是 Online Redo Log,按日志组循环写。
例如:
Group 1 -> Group 2 -> Group 3 -> Group 1但是旧日志组不是事务提交后马上覆盖。
一个 redo log group 要能被复用,需要满足:
不是 CURRENT 当前正在写 checkpoint 已完成 如果是 ARCHIVELOG 模式,必须已经归档完成查询 redo 状态:
【CDB$ROOT 执行】
set linesize 200 col member for a80 select l.group#, l.thread#, l.sequence#, round(l.bytes / 1024 / 1024, 2) as size_mb, l.status, l.archived, f.member from v$log l join v$logfile f on l.group# = f.group# order by l.thread#, l.group#;状态说明:
| 状态 | 含义 |
|---|---|
CURRENT | 当前正在写,不能复用 |
ACTIVE | 可能还用于实例恢复,暂时不能复用 |
INACTIVE | 可以复用 |
ARCHIVED=YES | 已归档 |
ARCHIVED=NO | 未归档 |
关键记法:
Redo 是日志组循环使用; 不是 commit 后立刻复用; 必须日志切换、checkpoint、归档完成后才能覆盖。23、归档日志是什么?什么时候生成?
数据库开启归档模式后,Online Redo Log 在日志切换后,会由 ARCn 归档进程复制成 Archived Redo Log,这就是归档日志。
查询归档模式:
【CDB$ROOT 执行】
archive log list;或者:
select log_mode from v$database;如果结果是:
LOG_MODE = ARCHIVELOG说明数据库已开启归档。
归档不是 commit 后生成。
正确流程:
DML 产生 redo COMMIT 时 LGWR 把 redo 写入当前 Online Redo Log 当前 redo log 写满,或者手动 switch logfile 发生 log switch ARCn 把旧日志组归档成 Archived Redo Log 归档完成后,旧日志组未来才允许被覆盖复用手动切日志命令:
【CDB$ROOT 执行,谨慎执行】
alter system switch logfile;生产环境不要随便频繁执行。
一句话:提交是把账记到账本里,归档是账本写满后复印存档。
24、最终总结
Oracle 误操作恢复不是一条路走到底,而是要根据误操作类型选择正确恢复路线:
DELETE / UPDATE: 优先看 UNDO,通过 Flashback Query 查询历史版本。 DROP TABLE: 优先看 Recycle Bin,通过 flashback table to before drop 恢复。 TRUNCATE TABLE: 普通回收站和 Flashback Query 通常救不了,要看 RMAN、归档日志、备库或历史备份。 整库级误操作: 看 Flashback Database、Restore Point、RMAN 和归档日志。 Redo 和归档日志: 负责故障恢复和介质恢复,不是给普通 SQL 直接查询历史数据用的。最终口诀:
整库回退:看 Flashback Database; 几分钟前误 DELETE:看 UNDO; 误 DROP TABLE:看 Recycle Bin; 误 TRUNCATE:看备份、归档、备库; 数据库级能力:在 CDB$ROOT 看; 业务对象恢复:进业务 PDB 查; Redo 循环复用:看 checkpoint 和归档状态; 归档日志生成:发生在日志切换后,不是 commit 后; FRA:不是只给闪回用,没开闪回也不是白配置。一句话总结:
数据库恢复不是靠一个功能包打天下,而是 DELETE 看 UNDO,DROP 看回收站,TRUNCATE 看备份,整库回退看 Flashback Database 或 RMAN。路径分清楚,事故才不慌。
