闪回技术详解

最后更新: 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)