闪回技术详解
最后更新: 2026-04-15
作者: Oracle Team
页面目录
第十四章:闪回技术详解
文档信息
- 适用版本:Oracle 12c / 18c / 19c / 21c
- 阅读时间:约 50 分钟
- 前置知识:第十一章备份与恢复
14.1 闪回技术概述
14.1.1 闪回技术家族
┌─────────────────────────────────────────────────────────────────┐
│ Oracle 闪回技术体系 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 闪回查询 (Flashback Query) │ │
│ │ • AS OF TIMESTAMP / SCN │ │
│ │ • 查看历史数据 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 闪回版本查询 (Flashback Version Query) │ │
│ │ • VERSIONS BETWEEN │ │
│ │ • 查看数据变更历史 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 闪回表 (Flashback Table) │ │
│ │ • 将表恢复到指定时间点 │ │
│ │ • 不需要脱机 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 闪回删除 (Flashback Drop) │ │
│ │ • RECYCLEBIN │ │
│ │ • 恢复已删除的表 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 闪回数据库 (Flashback Database) │ │
│ │ • 将整个数据库恢复到过去某个时间点 │ │
│ │ • 代替不完全恢复 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 闪回数据归档 (Flashback Data Archive) │ │
│ │ • 长期保留历史数据 │ │
│ │ • 可审计跟踪 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
14.1.2 前提条件
-- 必须启用行移动
ALTER TABLE employees ENABLE ROW MOVEMENT;
-- 闪回数据库需要启用闪回日志
ALTER DATABASE FLASHBACK ON;
-- 查看闪回是否启用
SELECT
flashback_on,
log_mode
FROM v$database;
-- 查看回收站
SELECT * FROM USER_RECYCLEBIN;
-- 或
SELECT * FROM RECYCLEBIN;
14.2 闪回查询
14.2.1 基于时间戳的闪回查询
-- 查询过去某个时间点的数据
SELECT * FROM employees AS OF TIMESTAMP
TO_TIMESTAMP('2024-01-15 10:00:00', 'YYYY-MM-DD HH24:MI:SS')
WHERE department_id = 50;
-- 查询最近 1 小时前的数据
SELECT * FROM employees AS OF TIMESTAMP SYSDATE - 1/24
WHERE department_id = 50;
-- 查询昨天这个时候
SELECT * FROM employees AS OF TIMESTAMP TRUNC(SYSDATE) - 1 + INTERVAL '14' HOUR;
-- 查看数据变化
SELECT
employee_id,
salary AS current_salary,
(SELECT salary FROM employees AS OF TIMESTAMP SYSDATE - 1) AS yesterday_salary
FROM employees
WHERE department_id = 50;
14.2.2 基于 SCN 的闪回查询
-- 获取当前 SCN
SELECT TIMESTAMP_TO_SCN(SYSTIMESTAMP) AS current_scn FROM DUAL;
-- 或者
SELECT DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER AS scn FROM DUAL;
-- 基于 SCN 查询
SELECT * FROM employees AS OF SCN 12345678;
-- SCN 与时间戳转换
SELECT SCN_TO_TIMESTAMP(12345678) FROM DUAL;
-- 查看某段时间内的 SCN
SELECT
BEGIN_INTERVAL_TIME,
END_INTERVAL_TIME,
CHECKPOINT_CHANGE# AS SCN
FROM DBA_HIST_SNAPSHOT
WHERE TIMESTAMP BETWEEN TO_TIMESTAMP('2024-01-15 09:00:00', 'YYYY-MM-DD HH24:MI:SS')
AND TO_TIMESTAMP('2024-01-15 10:00:00', 'YYYY-MM-DD HH24:MI:SS');
14.2.3 闪回查询示例
-- 场景:用户误删除数据后恢复
-- 1. 查看删除前的数据
SELECT * FROM employees AS OF TIMESTAMP
TO_TIMESTAMP('2024-01-15 09:30:00', 'YYYY-MM-DD HH24:MI:SS')
WHERE employee_id = 1000;
-- 2. 恢复数据
INSERT INTO employees
SELECT * FROM employees AS OF TIMESTAMP
TO_TIMESTAMP('2024-01-15 09:30:00', 'YYYY-MM-DD HH24:MI:SS')
WHERE employee_id = 1000;
-- 3. 或者更新当前数据
UPDATE employees e
SET (salary) = (
SELECT salary FROM employees AS OF TIMESTAMP
TO_TIMESTAMP('2024-01-15 09:30:00', 'YYYY-MM-DD HH24:MI:SS')
WHERE employee_id = e.employee_id
)
WHERE EXISTS (
SELECT 1 FROM employees AS OF TIMESTAMP
TO_TIMESTAMP('2024-01-15 09:30:00', 'YYYY-MM-DD HH24:MI:SS')
WHERE employee_id = e.employee_id
);
COMMIT;
14.3 闪回版本查询
14.3.1 闪回版本查询语法
-- 查看一段时间内数据的所有版本
SELECT
employee_id,
first_name,
salary,
VERSIONS_OPERATION AS op, -- I/U/D
VERSIONS_STARTTIME,
VERSIONS_ENDTIME,
VERSIONS_STARTSCN,
VERSIONS_ENDSCN,
VERSIONS_XID AS transaction_id
FROM employees
VERSIONS BETWEEN TIMESTAMP
TO_TIMESTAMP('2024-01-15 08:00:00', 'YYYY-MM-DD HH24:MI:SS')
AND TO_TIMESTAMP('2024-01-15 12:00:00', 'YYYY-MM-DD HH24:MI:SS')
WHERE employee_id = 1000
ORDER BY VERSIONS_STARTTIME;
-- 基于 SCN 的版本查询
SELECT
employee_id,
salary,
VERSIONS_OPERATION,
VERSIONS_STARTSCN,
VERSIONS_ENDSCN,
VERSIONS_XID
FROM employees
VERSIONS BETWEEN SCN 12340000 AND 12350000
WHERE employee_id = 1000;
14.3.2 查询结果解读
┌─────────────────────────────────────────────────────────────────┐
│ VERSIONS BETWEEN 查询结果示例 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ EMP_ID │ SALARY │ OP │ START_TIME │ END_TIME │
│ ───────┼────────┼────┼─────────────────────┼─────────────────────│
│ 1000 │ 5000 │ U │ 2024-01-15 10:30:00 │ 2024-01-15 11:00:00│
│ 1000 │ 4500 │ U │ 2024-01-15 09:00:00 │ 2024-01-15 10:30:00│
│ 1000 │ 4000 │ I │ 2024-01-15 08:00:00 │ │
│ │
│ OP: I=INSERT, U=UPDATE, D=DELETE │
│ 空 END_TIME 表示当前版本 │
│ │
└─────────────────────────────────────────────────────────────────┘
14.3.3 恢复误删除的行
-- 查找被删除的行
SELECT * FROM employees
VERSIONS BETWEEN TIMESTAMP
TO_TIMESTAMP('2024-01-15 08:00:00', 'YYYY-MM-DD HH24:MI:SS')
AND SYSTIMESTAMP
WHERE employee_id = 1000
AND VERSIONS_OPERATION = 'D';
-- 恢复已删除的行
INSERT INTO employees (
SELECT * FROM employees
VERSIONS BETWEEN TIMESTAMP
TO_TIMESTAMP('2024-01-15 08:00:00', 'YYYY-MM-DD HH24:MI:SS')
AND SYSTIMESTAMP
WHERE employee_id = 1000
AND VERSIONS_OPERATION = 'D'
);
14.4 闪回表
14.4.1 闪回表到指定时间
-- 必须启用行移动
ALTER TABLE employees ENABLE ROW MOVEMENT;
-- 闪回表到指定时间点
FLASHBACK TABLE employees TO TIMESTAMP
TO_TIMESTAMP('2024-01-15 10:00:00', 'YYYY-MM-DD HH24:MI:SS');
-- 闪回表到 SCN
FLASHBACK TABLE employees TO SCN 12345678;
-- 闪回表到还原点
FLASHBACK TABLE employees TO RESTORE POINT before_upgrade;
-- 闪回前后对比
SELECT * FROM employees AS OF TIMESTAMP SYSDATE - 1; -- 闪回前
SELECT * FROM employees; -- 闪回后
14.4.2 闪回表示例
-- 场景:批量更新后需要撤销
-- 1. 创建还原点
CREATE RESTORE POINT before_batch_update;
-- 2. 执行批量更新
UPDATE employees SET salary = salary * 1.1 WHERE department_id = 50;
COMMIT;
-- 3. 发现错误,闪回表
FLASHBACK TABLE employees TO RESTORE POINT before_batch_update;
-- 4. 清理还原点
DROP RESTORE POINT before_batch_update;
-- 查看所有还原点
SELECT
NAME,
SCN,
TIME,
GUARANTEE_FLASHBACK_DATABASE
FROM V$RESTORE_POINT;
14.4.3 闪回表限制
限制说明
以下情况不能使用闪回表:
- 表结构被修改(DDL)
- 表被删除
- 表已 Truncate
- 涉及引用完整性约束(外键)
14.5 闪回删除
14.5.1 回收站机制
-- 查看回收站
SELECT
object_name,
original_name,
type,
droptime,
space
FROM user_recyclebin;
-- 或者使用 DBA_RECYCLEBIN(需要 DBA 权限)
SELECT * FROM DBA_RECYCLEBIN WHERE owner = 'HR';
-- 回收站命名规则
-- BIN$globalUID$version
-- 例如: BIN$ABC123XYZ==$0
14.5.2 恢复删除的表
-- 方式1:使用回收站中原名
FLASHBACK TABLE employees TO BEFORE DROP;
-- 方式2:使用回收站中的名称恢复
FLASHBACK TABLE "BIN$ABC123XYZ==$0" TO BEFORE DROP;
-- 恢复并重命名
FLASHBACK TABLE "BIN$ABC123XYZ==$0" TO BEFORE DROP RENAME TO employees_old;
-- 恢复被删除的表到特定时间
FLASHBACK TABLE employees TO BEFORE DROP
TO TIMESTAMP TO_TIMESTAMP('2024-01-15 09:00:00', 'YYYY-MM-DD HH24:MI:SS');
14.5.3 管理回收站
-- 清除回收站
PURGE TABLE employees; -- 清除特定表
PURGE TABLE "BIN$ABC123XYZ==$0";
-- 清除整个用户回收站
PURGE RECYCLEBIN;
-- DBA 清除所有回收站
PURGE DBA_RECYCLEBIN;
-- 手动删除而不进回收站
DROP TABLE employees PURGE;
-- 禁用回收站(需要 DBA 权限)
ALTER SYSTEM SET recyclebin = OFF SCOPE = SPFILE;
14.6 闪回数据库
14.6.1 闪回数据库原理
┌─────────────────────────────────────────────────────────────────┐
│ 闪回数据库原理 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 前提条件:启用闪回日志 │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 闪回日志 (Flashback Logs) │ │
│ │ • 记录数据块的前镜像 │ │
│ │ • 存储在闪回恢复区 │ │
│ │ • 自动管理 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ 恢复过程: │
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
│ │ Flashback │ → │ Redo App │ → │ Open │ │
│ │ Database │ │ (可选) │ │ Resetlogs│ │
│ └───────────┘ └───────────┘ └───────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
14.6.2 启用闪回数据库
-- 1. 确保数据库处于归档模式
ARCHIVE LOG LIST;
-- 2. 配置闪回恢复区
ALTER SYSTEM SET DB_RECOVERY_FILE_DEST = '/u01/app/oracle/fra' SCOPE=SPFILE;
ALTER SYSTEM SET DB_RECOVERY_FILE_DEST_SIZE = 100G SCOPE=SPFILE;
-- 3. 启用闪回日志
SHUTDOWN IMMEDIATE;
STARTUP MOUNT;
ALTER DATABASE FLASHBACK ON;
ALTER DATABASE OPEN;
-- 4. 查看闪回配置
SELECT
flashback_on,
retention_target -- 保留目标(分钟)
FROM v$database;
-- 5. 修改保留时间
ALTER DATABASE FLASHBACK ON RETENTION TARGET TO 1440; -- 保留 1 天
-- 6. 查看闪回日志使用空间
SELECT
ROUND(SPACE_USED/1024/1024/1024, 2) AS used_gb,
ROUND(SPACE_LIMIT/1024/1024/1024, 2) AS limit_gb
FROM v$recovery_file_dest;
14.6.3 执行闪回数据库
-- 1. 启动到 MOUNT 状态
SHUTDOWN IMMEDIATE;
STARTUP MOUNT;
-- 2. 执行闪回(基于时间戳)
FLASHBACK DATABASE TO TIMESTAMP
TO_TIMESTAMP('2024-01-15 10:00:00', 'YYYY-MM-DD HH24:MI:SS');
-- 3. 或者基于 SCN
FLASHBACK DATABASE TO SCN 12345678;
-- 4. 或者基于还原点
FLASHBACK DATABASE TO RESTORE POINT before_error;
-- 5. 以只读模式打开验证
ALTER DATABASE OPEN READ ONLY;
-- 6. 如果满意,执行 resetlogs
ALTER DATABASE OPEN RESETLOGS;
-- 7. 如果不满意,继续闪回或执行恢复
-- SHUTDOWN IMMEDIATE
-- STARTUP MOUNT
-- RECOVER DATABASE -- 使用普通恢复
14.6.4 闪回数据库示例
-- 场景:执行了错误的批量更新
-- 1. 创建还原点(确保闪回可用)
CREATE RESTORE POINT before_bad_batch GUARANTEE FLASHBACK DATABASE;
-- 2. 执行批量更新(发现问题)
BEGIN
FOR rec IN (SELECT employee_id FROM employees WHERE department_id = 50) LOOP
UPDATE employees SET salary = 100 WHERE employee_id = rec.employee_id;
END LOOP;
COMMIT;
END;
/
-- 3. 所有工资变成 100,立即闪回
SHUTDOWN IMMEDIATE;
STARTUP MOUNT;
-- 4. 闪回到还原点
FLASHBACK DATABASE TO RESTORE POINT before_bad_batch;
-- 5. 验证数据
ALTER DATABASE OPEN READ ONLY;
-- 检查工资是否恢复正常
SELECT COUNT(*) FROM employees WHERE salary = 100; -- 应该为 0
SELECT COUNT(*) FROM employees WHERE salary > 1000; -- 应该有很多
-- 6. 确认无误后打开
SHUTDOWN IMMEDIATE;
STARTUP MOUNT;
ALTER DATABASE OPEN RESETLOGS;
-- 7. 清理还原点
DROP RESTORE POINT before_bad_batch;
14.7 闪回数据归档
14.7.1 创建闪回数据归档
-- 1. 创建闪回数据归档表空间
CREATE TABLESPACE fbda_ts
DATAFILE '/u01/app/oracle/oradata/ORCL/fbda01.dbf'
SIZE 1G;
-- 2. 创建闪回数据归档
CREATE FLASHBACK ARCHIVE DEFAULT fbda_1year
TABLESPACE fbda_ts
RETENTION 1 YEAR;
-- 创建不带 DEFAULT 的归档
CREATE FLASHBACK ARCHIVE fbda_2years
TABLESPACE fbda_ts
RETENTION 2 YEAR;
-- 3. 为表启用闪回归档
ALTER TABLE employees FLASHBACK ARCHIVE fbda_1year;
-- 4. 验证
SELECT
table_name,
flashback_archive_name,
retention_in_days
FROM user_flashback_archive_tables;
-- 5. 查询历史数据
SELECT * FROM employees
AS OF TIMESTAMP TO_TIMESTAMP('2023-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS');
-- 6. 禁用表归档
ALTER TABLE employees NO FLASHBACK ARCHIVE;
-- 7. 删除归档
DROP FLASHBACK ARCHIVE fbda_1year;
14.7.2 闪回数据归档查询
-- 查询多年前的员工数据(即使普通 UNDO 已过期)
SELECT
employee_id,
first_name,
salary,
hire_date
FROM employees
AS OF TIMESTAMP TO_TIMESTAMP('2020-06-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS')
WHERE department_id = 50;
-- 对比不同时间点的数据
SELECT
e1.employee_id,
e1.salary AS salary_2020,
e2.salary AS salary_now
FROM
(SELECT * FROM employees AS OF TIMESTAMP TO_TIMESTAMP('2020-06-01', 'YYYY-MM-DD')) e1,
employees e2
WHERE e1.employee_id = e2.employee_id;
14.8 闪回技术与 RMAN 恢复对比
| 特性 | 闪回技术 | RMAN 恢复 |
|---|---|---|
| 恢复范围 | 表级/行级 | 表空间/数据库级 |
| 恢复速度 | 快(秒级) | 慢(分钟/小时) |
| 停机时间 | 极短 | 较长 |
| 数据丢失 | 闪回时间内无丢失 | 恢复到备份点 |
| 前提条件 | UNDO/Flashback Log | 备份集 |
| 适用场景 | 误操作恢复 | 灾难恢复 |
14.9 本章小结
✅ 闪回查询 (AS OF):查看历史数据,无需恢复
✅ 闪回版本查询 (VERSIONS BETWEEN):查看数据变更历史
✅ 闪回表 (FLASHBACK TABLE):将表恢复到过去某个时间点
✅ 闪回删除 (RECYCLEBIN):恢复误删除的表
✅ 闪回数据库 (FLASHBACK DATABASE):将整个数据库恢复到过去
✅ 闪回数据归档:长期保留历史数据(审计追踪)
📖 下章预告:日志挖掘(LogMiner)
下一步:学习 第十五章:日志挖掘(LogMiner)