作者 | JiekeXu
来源 |公众号 JiekeXu DBA之路(ID: JiekeXu_IT)
如需转载请联系授权
大家好,我是 JiekeXu,很高兴又和大家见面了,今天和大家一起来学习19c 新特性 |ADG 备库支持 DML 重定向
在 19c 中有众多的新特性,官方上有一个专门收集新特性的网站,从 11g 到 21c 均有涉及,并且每一个新特性都对应了官方文档,仅 19c 新特性就有 118 个。
在 19c 版本中,ADG 中的备库(PS:19c ADG 备库搭建可点击此处链接查看)支持 DML 操作,原理是:是通过将备库上的 DML 重定向到主库上执行,然后备库应用 DML 变化数据,至此完成备库 DML 操作。
DML 重定向整体的步骤如下: 1.备库的客户端发起 DML 操作。 2.备库的 DML 操作通过内部的 dblink 被重定向到主库执行。 3.DML 语句在主库被实施。 4.主库生成更改的 redo log 传到备库。 5.备库应用此日志完成 DML 重定向,客户端显示修改后的数据信息。
这个新特性的功能是: 将偶然发送到 ADG上的DML操作,自动转发到主库执行,然后通过主库日志传递到备库实时应用,在保证了ACID的前提下,大大增强了备库的实用性,这被称为 DML Redirection 。这个功能其实在 18c 就已经支持了,在 18c 是作为隐含参数 _enable_proxy_adg_redirect 调整的,在 19c 中,通过显式参数 ADG_REDIRECT_DML 参数调整。官方文档中描述如下:
您可以在 Active Data Guard 备用数据库上运行 DML 操作。这使您能够在备用数据库上运行以读取为主的应用程序,这些应用程序偶尔会执行 DML。
备用数据库上的 DML 操作可以透明地重定向到主数据库并在其上运行。这包括作为 PL/SQL 块一部分的 DML 语句。Active Data Guard 会话一直等待,直到相应的更改被传送并应用到 Active Data Guard 备用数据库。在 DML 操作期间保持读取一致性,运行 DML 的备用数据库可以查看其未提交的更改。但是,所有其他备用数据库实例只有在事务提交后才能查看这些更改。
避免在 Active Data Guard 备用数据库上运行过多的 DML 操作。因为这些操作实际上是在主节点上执行的,所以过多的 DML 可能会影响主节点的性能。Active Data Guard 备用数据库不支持 XA 事务中的 DML 操作。
可以在系统级别或会话级别配置 DML 操作到主服务器的自动重定向。会话级别设置覆盖系统级别设置。
要为 Active Data Guard 环境中的所有备用会话配置 DML 操作的自动重定向:
- 将
ADG_REDIRECT_DML
初始化参数设置为TRUE
。
要为当前会话配置 DML 操作的自动重定向,请使用以下命令:
ALTER SESSION ENABLE ADG_REDIRECT_DML;
下面一起看看具体的例子:
代码语言:javascript复制--19c 实时同步的 ADG 环境
sqlplus / as sysdba
SQL*Plus: Release 19.0.0.0.0 - Production
on Fri Jul 29 11:34:04 2022
Version 19.15.0.0.0
Copyright (c) 1982, 2022, Oracle.All rights reserved.
Connected to:
Oracle Database 19c Enterprise Edition
Release 19.0.0.0.0 - Production
Version 19.15.0.0.0
SQL> select
INST_ID,open_mode,LOG_MODE,DATABASE_ROLE,PROTECTION_MODE fromgv$database;
INST_ID OPEN_MODE LOG_MODE DATABASE_ROLE PROTECTION_MODE
---------- --------------------
------------ ---------------- --------------------
1 READ ONLY WITH APPLY ARCHIVELOG PHYSICAL STANDBY MAXIMUM PERFORMANCE
Elapsed: 00:00:00.03
SQL> set lin 1000
SQL> set pagesize 20;
column name format a13;
SQL> SQL> column value format a20;
column unit format a30;
column TIME_COMPUTED format a30;
select name,value,unit,time_computed from
v$dataguard_stats where name in ('transport lag','apply lag');
SQL> SQL> SQL>
NAMEVALUE UNIT DATUM_TIME TIME_COMPUTED
------------- --------------------
------------------------------ ------------------------------
------------------------------
transport lag 00 00:00:00 day(2) to second(0) interval 07/29/2022 14:43:21 07/29/2022 14:43:22
apply lag 00 00:00:00 day(2) to second(0) interval 07/29/2022 14:43:21 07/29/2022 14:43:22
一、会话级别修改参数
进行 DDL 操作,备库只读,必然会报错。
代码语言:javascript复制SQL> create table test1 (id int,name
varchar2(20));
create table test1 (id int,name
varchar2(20))
*
ERROR at line 1:
ORA-16000: database or pluggable database
open for read-only access
SQL> show parameter ADG_REDIRECT_DML
NAMETYPE VALUE
------------------------------------
----------- ------------------------------
adg_redirect_dmlboolean FALSE
SQL> show user
USER is "SYS"
前面说了 DML 重定向参数可以有会话级别和实例级别的设置。自动重定向 DML 操作 ADG_REDIRECT_DML 参数支持会话级别和系统级别,会话级别会覆盖系统级别配置。
1)SYS 系统级别
然后先在 SYS、SYSTEM 用户上尝试会话级别的 DML 重定向功能。
代码语言:javascript复制--当前会话启用 DML 重定向
ALTER SESSION ENABLE ADG_REDIRECT_DML;
DDL 语句不支持
DML 语句报错 ORA-16397
System 进行测试,DDL 还是和预想的一样不能执行,但 DML 语句是支持的,insert 一条数据已经插入到 test 用户下。
2)普通用户级别
在普通用户上尝试
代码语言:javascript复制SQL> insert into T_TMP_USER_JIEKE values
(2,'jieke','select 1 from dual;','DML');
insert into T_TMP_USER_JIEKE values
(2,'jieke','select 1 from dual;','DML')
*
ERROR at line 1:
ORA-01157: cannot
identify/lock data file 2049 - see DBWR trace file
ORA-01110: data file 2049: '/data/jiekedbstb/tempfile/temp.280.1104593777
此错误是由于备库刚搭建完成,临时表空间文件没有在备库生成,建立相应的目录,重启备库则会自动生成临时表空间文件。
代码语言:javascript复制$ ll
/data/jiekedbstb/tempfile/temp.280.1104593777
ls: cannot access
/data/jiekedbstb/tempfile/temp.280.1104593777: No such file or directory
$ cd /data/jiekedbstb/tempfile
-bash: cd: /data/jiekedbstb/tempfile: No
such file or directory
mkdir -p /data/jiekedbstb/tempfile
15:34:27 SQL> shu immediate
Database closed.
Database dismounted.
ORACLE instance shut down.
15:34:58 SQL> startup
ORACLE instance started.
Total System Global Area 1.2885E 10 bytes
Fixed Size13629520 bytes
Variable Size3858759680 bytes
Database Buffers8992587776 bytes
Redo Buffers19922944 bytes
Database mounted.
Database opened.
SQL> ALTER DATABASE RECOVER MANAGED
STANDBY DATABASE DISCONNECT;
SQL> select name,value,unit,datum_time,time_computed from v$dataguard_stats where name in
('transport lag','apply lag');
普通用户 DML 可以正常插入。
二、系统级别修改参数
在备库上启用 DML 重定向将初始化参数 ADG_REDIRECT_DML 设置为 true。
代码语言:javascript复制ALTER SYSTEM SET ADG_REDIRECT_DML=true SCOPE=BOTH;
登录普通用户可以进行数据插入的操作。
代码语言:javascript复制17:23:34 SQL> conn test/TEST
Connected.
17:23:39 SQL>
17:23:40 SQL> select * from tab;
TNAME TABTYPE CLUSTERID
--------------------------------------------------------------------------------------------------------------------------------
------------- ----------
T_TMP_USER_JIEKE TABLE
Elapsed: 00:00:00.01
17:23:49 SQL> insert into
T_TMP_USER_JIEKE values (5,'jieke','select 5 from dual;','DML');
1 row created.
Elapsed: 00:00:00.10
17:25:43 SQL> commit;
Commit complete.
现在来试试 sys 系统用户,执行 DML 操作。
先在主库创建一张 test.t1表,然后到备库去做 DML 操作。
代码语言:javascript复制SQL> create table test.t1 as select *
from dba_objects;
Table created.
SQL> select count(*) from test.t1;
COUNT(*)
----------
138662
SQL> select min(OBJECT_ID) from test.t1;
MIN(OBJECT_ID)
--------------
2
然后在备库 SYS 用户执行报错 ORA-16397
代码语言:javascript复制SQL> select min(OBJECT_ID) from test.t1;
MIN(OBJECT_ID)
--------------
2
Elapsed: 00:00:00.04
SQL> show user
USER is "SYS"
SQL> delete from test.t1 where OBJECT_ID=2;
delete from test.t1 where OBJECT_ID=2
*
ERROR at line 1:
ORA-16397: statement redirection from
Oracle Active Data Guard standby database to primary database failed
报错原因:不支持 SYS 用户会话级别启用 DML 重定向,当然 19c 本身 SYS 用户下新建表也不会同步到备库,那么来试试 SYSTEM.
那么使用 system 用户主库建个表测试一下
代码语言:javascript复制SQL> conn system/Oracle
SQL> Connected.
SQL> create table system.test1 (id
int,name varchar2(20));
Table created.
SQL> select * from system.test1;
no rows selected
SQL> insert into system.test1
values(1,'jiekexu');
1 row created.
SQL> commit;
Commit complete.
SQL>select * from system.test1;
ID NAME
---------- --------------------
1 jiekexu
备库:
代码语言:javascript复制SQL> show user
USER is "SYSTEM"
SQL>
SQL> select INST_ID,open_mode,LOG_MODE,DATABASE_ROLE,PROTECTION_MODE
fromgv$database;
INST_ID OPEN_MODE LOG_MODE DATABASE_ROLE PROTECTION_MODE
---------- --------------------
------------ ---------------- --------------------
1 READ ONLY WITH APPLY ARCHIVELOG PHYSICAL STANDBY MAXIMUM PERFORMANCE
SQL> insert into system.test1
values(2,'jieke');
1 row created.
Elapsed: 00:00:00.13
SQL> commit;
三、跟踪 10046 trace 查看具体过程
代码语言:javascript复制--主库:grant alter session to test;
--备库:alter session set events '10046 trace name context forever ,level 12';
insert into TEST.T_TMP_USER_JIEKE values(7,'dba','select 7 from dual;','DML');
alter session set events '10046 trace name context off';
select distinct(m.sid),p.pid,p.tracefile from v$mystat m,v$session s,v$process p where m.sid=s.sid and s.paddr=p.addr;
--有可能这样没有找到对应的 trace,使用下面的方法。
alter session set tracefile_identifier='10046TEST';
alter session set events '10046 trace name context forever ,level 12';
insert into TEST.T_TMP_USER_JIEKE values(7,'dba','select 7 from dual;','DML');
alter session set events '10046 trace name context off';
通过后台的跟踪日志,可以看到,DML 操作是通过 DB Link 来重定向到主库执行的,这个DB Link 是内部的,在服务名等配置正常情况下,能够自动完成内部操作。
代码语言:javascript复制=====================
PARSING IN CURSOR
#140321356468712 len=78 dep=0 uid=108 oct=2 lid=108 tim=1559487590897
hv=406207236 ad='ff8871b0' sqlid='13fa7w4c3cfs4'
insert into TEST.T_TMP_USER_JIEKE
values(8,'dba','select 8 from dual;','DML')
END OF STMT
PARSE #140321356468712:c=4647,e=5629,p=0,cr=2,cu=0,mis=1,r=0,dep=0,og=1,plh=0,tim=1559487590896
WAIT
#140321356468712: nam='SQL*Net message to dblink' ela= 2 driver id=1413697536
#bytes=1 p3=0 obj#=-1 tim=1559487591138
WAIT
#140321356468712: nam='SQL*Net message from dblink' ela= 3224 driver
id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1559487594416
EXEC
#140321356468712:c=500,e=3530,p=0,cr=0,cu=0,mis=0,r=1,dep=0,og=1,plh=0,tim=1559487594523
WAIT
#140321356468712: nam='PGA memory operation' ela= 60 p1=0 p2=0 p3=0 obj#=-1
tim=1559487594671
WAIT
#140321356468712: nam='SQL*Net message to client' ela= 3 driver id=1650815232
#bytes=1 p3=0 obj#=-1 tim=1559487594720
WAIT
#140321356468712: nam='SQL*Net message from client' ela= 479 driver
id=1650815232 #bytes=1 p3=0 obj#=-1 tim=1559487595229
PARSE
#140321356505176:c=50,e=50,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=0,tim=1559487595377
BINDS
#140321356505176:
tkprof 格式化输出
代码语言:javascript复制tkprof /u01/app/oracle/diag/rdbms/jiekedbstb/jiekedbstb/trace/jiekedbstb_ora_4372.trc ./adg_dml.log
通过格式化输出后可以明显看到 insert 后调用了 dblink,DML 操作通过内部的 DBLink 到主库执行后应用日志到备库再将结果返回到备库客户端。
除了常规表之外, 还支持在备库创建全局临时表,执行 PL/SQL 等操作,可以在 Active Data Guard 备用数据库上创建和删除全局临时表。这些操作的 DDL 被透明地重定向到主数据库。然后,Active Data Guard 会话将等待相应的更改发送并应用到 Active Data Guard 备用服务器。在 19c 中,隐含参数 _alter_adg_redirect_behavior 可以用于定义允许重定向的级别,例如当设置为 disallow_gtt 将不允许重定向全局临时表。
全文完,希望可以帮到正在阅读的你