
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、不同误操作对应的恢复路线误操作类型优先恢复方向核心依赖DELETEFlashback QueryUNDOUPDATEFlashback QueryUNDODROP TABLERecycle Bin回收站TRUNCATE TABLERMAN / 归档 / 备库备份恢复能力整库误操作Flashback Database / RMANFlashback 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$ROOTalter session set containerCDB$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 DatabaseNO未开启数据库级 Flashback DatabaseRESTORE 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 PointRestore 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 LogFlashback 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-30036UNDO 表空间无法扩展 出现 ORA-01555snapshot 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;字段说明字段含义SSOLDERRCNTORA-01555 次数NOSPACEERRCNTUNDO 空间不足次数TUNED_UNDORETENTIONOracle 实际调优后的 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 QueryTRUNCATE不能靠回收站通常靠备份、归档、备库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 QueryREDO实例恢复、介质恢复、归档恢复、Data Guard常见操作操作UNDOREDOINSERT有有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可以复用ARCHIVEDYES已归档ARCHIVEDNO未归档关键记法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 看 UNDODROP 看回收站TRUNCATE 看备份整库回退看 Flashback Database 或 RMAN。路径分清楚事故才不慌。