Active Data Guard DML 重定向 是 Oracle 19c 引入的一项重要新特性,允许在 物理备库(Physical Standby) 上直接执行 DML 操作(INSERT、UPDATE、DELETE)。当用户在备库上发起 DML 时,操作会被 透明地重定向 到主库执行,产生的 Redo 日志再传回备库应用,最终将结果返回给客户端。
此特性使得备库不再仅限于只读查询,而是可以承载 "偶尔写入" 的混合工作负载,真正实现 Read-Mostly 架构。
┌─────────────────────────────────────────────────────────────┐
│ 应用层(客户端) │
│ 连接备库,发出 DML 语句(INSERT/UPDATE/DELETE) │
└──────────────────────┬──────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Active Data Guard 备库 │
│ │
│ ① 接收 DML 请求 │
│ ② 自动检测是否为 DML 操作 │
│ ③ 将 DML 重定向到主库(透明,应用无感知) │
│ ④ 等待主库执行完毕并传回 Redo │
│ ⑤ Redo 应用后,返回结果给客户端 │
└──────────────────────┬──────────────────────────────────────┘
│ 重定向 (ADG_REDIRECT_DML)
▼
┌─────────────────────────────────────────────────────────────┐
│ 主库(Primary) │
│ │
│ ① 接收来自备库的重定向 DML │
│ ② 在本地执行 DML 操作 │
│ ③ 生成 Redo 日志 │
│ ④ 按 Data Guard 同步策略传送到备库 │
└─────────────────────────────────────────────────────────────┘步骤 | 说明 |
|---|---|
1 | 客户端连接到备库,发起 DML 语句(INSERT / UPDATE / DELETE) |
2 | 备库检测到 DML 操作,通过 ADG_REDIRECT_DML 机制将其 透明重定向 到主库 |
3 | 主库执行该 DML,生成 Redo 日志,提交事务 |
4 | 主库将 Redo 传输到备库,MRP(Managed Recovery Process)应用 Redo |
5 | 备库应用变更后,返回成功结果给客户端,DML 会话期间保持读一致性 |
优势 | 说明 |
|---|---|
🔄 Read-Mostly 负载分担 | 备库可同时处理只读查询和偶发写入,分担主库压力 |
⚡ 减少主库压力 | 大量的 SELECT 查询转移到备库,主库专注处理写入 |
🔌 无需修改应用 | 备库 DML 对应用完全透明,连接字符串无需变更 |
✅ 完整 ACID 保障 | 事务特性完全保留,数据一致性有保障 |
🛡️ 高可用增强 | 备库在容灾之外获得更多实用价值 |
在启用 DML 重定向之前,必须满足以下条件:
条件 | 要求 |
|---|---|
Oracle 版本 | 19c 或更高版本(19.0.0.0.0 及以上) |
Data Guard 配置 | 已配置 Data Guard Broker(建议) |
备库状态 | 物理备库,处于 READ ONLY WITH APPLY 模式 |
网络连接 | 主库和备库之间网络通畅,连接字符串可用 |
⚠️ 重要限制
sqlplus user/pass@standby),不能使用 / as sysdba-- 在备库执行SELECT OPEN_MODE, DATABASE_ROLE, SWITCHOVER_STATUS, PROTECTION_MODE, FLASHBACK_ON FROM V$DATABASE;预期输出:
OPEN_MODE = READ ONLY WITH APPLYDATABASE_ROLE = PHYSICAL STANDBY参数
ADG_REDIRECT_DML默认值为FALSE。需要在 主库和备库两端 都设置为TRUE。
SQL>show parameter adg_redirect_dml
NAME TYPE VALUE
———————————— ———– ——————————
adg_redirect_dml boolean FALSE
SQL>altersystemset adg_redirect_dml=true scope=both;
System altered.
SQL>show parameter adg_redirect_dml
NAME TYPE VALUE
———————————— ———– ——————————
adg_redirect_dml boolean TRUESQL>show parameter adg_redirect_dml
NAME TYPE VALUE
———————————— ———– ——————————
adg_redirect_dml boolean FALSE
SQL>altersystemset adg_redirect_dml=true scope=both;
System altered.
SQL>show parameter adg_redirect_dml
NAME TYPE VALUE
———————————— ———– ——————————
adg_redirect_dml boolean TRUE若仅需单个会话启用,而非全局启用:
-- 在当前会话启用 DML 重定向(会覆盖系统级设置)
ALTERSESSIONENABLE ADG_REDIRECT_DML;
-- 在当前会话禁用 DML 重定向
ALTERSESSIONDISABLE ADG_REDIRECT_DML;优先级:会话级设置 > 系统级设置
-- 连接主库(用户名/密码方式)
sqlplus sys/oracle@primaryas sysdba
-- 创建测试表
CREATETABLE oracle_dml_test (
name VARCHAR2(50),
testdate TIMESTAMP
);
-- 插入测试数据
INSERTINTO oracle_dml_test VALUES('主库写入测试', SYSDATE);
INSERTINTO oracle_dml_test VALUES('初始数据', SYSDATE);
COMMIT;
-- 验证
SELECT*FROM oracle_dml_test;-- 连接备库(必须使用用户名/密码方式,不可用 / as sysdba)
sqlplus sys/oracle@standbyas sysdba
-- 查看主库创建的表和数据是否已同步(可能在备库需要完全路径或等待 apply 延迟)
SELECT*FROM oracle_dml_test;
-- 确认备库状态
SELECT DATABASE_ROLE, OPEN_MODE FROM V$DATABASE;
SELECTSTATUS, INSTANCE_NAME, DATABASE_ROLE, PROTECTION_MODE
FROM V$DATABASE, V$INSTANCE;预期输出:
DATABASE_ROLE OPEN_MODE
-------------------- --------------------
PHYSICAL STANDBY READ ONLY WITH APPLY-- 连接备库(用户名/密码,非 SYS 用户优先)
sqlplus test_user/test_pass@standby
-- 在备库执行 DELETE 操作(将会被透明重定向到主库)
DELETEFROM oracle_dml_test WHERE name ='初始数据';
-- 显示受影响行数
-- 输出: 1 row deleted.
-- 提交事务
COMMIT;
-- 再次查询,确认读一致性
SELECT*FROM oracle_dml_test;-- 连接主库
sqlplus sys/oracle@primaryas sysdba
-- 验证数据已从备库删除
SELECT*FROM oracle_dml_test;
-- 预期:'初始数据' 行已不存在,DML 重定向成功备库上的 PL/SQL 块中包含的 DML 同样会被重定向:
-- 在备库执行
BEGIN
INSERTINTO oracle_dml_test VALUES('PL/SQL 插入测试', SYSDATE);
UPDATE oracle_dml_test SET name ='PL/SQL 已更新'WHERE name ='PL/SQL 插入测试';
COMMIT;
END;
/-- 备库:插入后未提交,本会话可看到
INSERTINTO oracle_dml_test VALUES('未提交数据', SYSDATE);
SELECT*FROM oracle_dml_test; -- 可以看到新行
-- 另开一个备库会话(同一事务未提交前),看不到新行-- 备库执行多表操作
INSERTINTO oracle_dml_test VALUES('多表测试A', SYSDATE);
UPDATE oracle_dml_test SET testdate = SYSDATE WHERE name LIKE'多表%';
DELETEFROM oracle_dml_test WHERE name ='多表测试A';
COMMIT;-- 当前会话是否启用 DML 重定向
SELECT SYS_CONTEXT('USERENV','ADG_REDIRECT_DML')AS adg_redirect_enabled FROMDUAL;-- 查看 DML 重定向相关等待事件
SELECTevent, total_waits, time_waited, average_waitFROM V$SYSTEM_EVENTWHERE eventLIKE'%ADG%'OReventLIKE'%redirect%';常见错误代码:
错误码 | 说明 | 解决方案 |
|---|---|---|
ORA-16397 | 从备库到主库的语句重定向失败 | 检查主库连通性和 ADG_REDIRECT_DML 参数 |
ORA-00604 | 递归 SQL 级别 1 发生错误 | 通常因使用 / as sysdba 连接导致,改用用户名/密码 |
ORA-16000 | 备库上不支持的操作 | 确认操作类型为 DML(非 DDL) |
实践 | 说明 |
|---|---|
控制重定向占比 < 10% | 备库 DML 最终在主库执行,过多 DML 会冲击主库性能 |
使用非 SYS 用户 | 创建专用应用用户执行备库 DML,避免 SYS 限制 |
监控主库负载 | 关注主库的 DB TIME 和 Redo 生成速率 |
设置合理的网络延迟阈值 | 重定向对网络延迟敏感,建议主备之间延迟 < 5ms |
优先使用会话级别启用 | 默认关闭,仅对需要的会话启用,减少意外 DML 风险 |
测试环境中充分验证 | 上线前模拟备库 DML 压力,确认主库可承受 |
ORA-16397: statement redirection from Oracle Active Data Guard standby database to primary database failed排查步骤:
ADG_REDIRECT_DML 参数是否都为 TRUEREAD ONLY WITH APPLY 模式/ as sysdba 连接备库-- 检查备库是否启用了 DML 重定向
ALTERSESSIONENABLE ADG_REDIRECT_DML;
-- 检查连接方式
SELECT SYS_CONTEXT('USERENV','AUTHENTICATION_METHOD')FROMDUAL;
-- 应返回非 SYSDBA 认证方式V$ADG_STATS 视图诊断同步延迟-- 查看 ADG 同步状态
SELECT NAME,VALUE, TIME_COMPUTED, DATUM_TIME
FROM V$ADG_STATS
WHERE NAME LIKE'%lag%';