おらくるのいる生活

OracleのDBAとしての、障害対応やらパフォーマンス・チューニングやらの日々を綴っています

Active Data Guard DMLリダイレクトの検証

もう2020年になりましたが、去年の暮、19c新機能の検証をしていたので、紹介していきます。

まずはActive Data Guard DMLリダイレクトの検証で、検証に使用した環境は以下の通りです。

Oracle RAC(2ノード) EE 19.5.0.0.0

Oracle Linux Server release 7.6

 EXADATA DATABASE MACHINE X6-2

 Active Data Guard DMLリダイレクトの概要は以下の通りです。

スタンバイ・データベースで発行したDMLはプライマリ・データベースにリダイレクトされて実行される。
プライマリ・データベースで実行されたDMLがスタンバイ・データベースに伝搬されると、スタンバイ・データベースのセッションから更新された内容が見えるようになる。
高頻度のDMLは想定していない。

スタンバイ側でDMLの発行は出来るけれど、実際に実行されるのはあくまでプライマリ側だというのがポイントですね。

さもないと、更新可能スナップショット*1のようにコンフリクトの解消が必要になってきます。

 

以下、検証です。

まずはActive Data Guardを構築します。構成は以下の通りです。

DGMGRL> show configuration;

Configuration - orcl_active_dg

Protection Mode: MaxPerformance
Members:
orcl - Primary database
orcldg - Physical standby database

Fast-Start Failover: Disabled

Configuration Status:
SUCCESS (status updated 64 seconds ago)

 

スタンバイ側からinsertを実行してみます。

SQL> select count(*) from t1;
COUNT(*)
----------
142523903

SQL> insert into t1(col1) values(1);
insert into t1(col1) values(1)
*
ERROR at line 1:
ORA-16000: database or pluggable database open for read-only access

ADG_REDIRECT_DMLが有効でないと上記の通りエラーになるので、システムまたはセッション単位で有効にします。

SQL> ALTER SESSION ENABLE ADG_REDIRECT_DML;
Session altered.

SQL> insert into t1(col1) values(1);
1 row created.
SQL> select count(*) from t1;
COUNT(*)
----------
142523904

commitする前に結果を確認できていますね。

当然、ロールバックすれば更新前の状態が参照できます。

SQL> rollback;
Rollback complete.

SQL> select count(*) from t1;
COUNT(*)
----------
142523903

 ちなみに、普通の初期化パラメータと同じ構文で設定しようとするとエラーになります。

SQL> alter session set adg_redirect_dml=true;
alter session set adg_redirect_dml=true
*
ERROR at line 1:
ORA-02096: specified initialization parameter is not modifiable with this
option

 

「高頻度のDMLは想定していない」との事なので、やったらどうなるのか検証します。

プライマリ側

SQL> begin
2 for i in 1..100 loop
3 insert into t1(col1) values(i);
4 end loop;
5 end;
6 /

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.07

スタンバイ側

SQL> begin
2 for i in 1..100 loop
3 insert into t1(col1) values(i);
4 end loop;
5 end;
6 /

PL/SQL procedure successfully completed.

Elapsed: 00:01:33.47

プライマリで 0.07秒の処理が、1分半もかかります。

 

どこで時間がかかっているのか確認する為、SQLトレースを取得してみました。

call   count    cpu   elapsed disk    query   Current  rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse   2   0.00   0.00   0        0     0    0
Execute  2   0.01   93.35    0        0     0    1
Fetch   0   0.00   0.00   0        0     0    0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total   4   0.02  93.35   0       0      0    1


Elapsed times include waiting on following events:
Event waited on                                  Times  Max. Wait Total Waited
---------------------------------------- Waited ---------- ------------
Disk file operations I/O                              48         0.00          0.00
single-task message                                    1          0.01          0.01
SQL*Net message from dblink                210          0.01          0.09
SQL*Net message to dblink                    209          0.00          0.00
SQL*Net vector data to dblink                101          0.00          0.00
standby query scn advance                     100         1.05         93.30
********************************************************************************

 処理時間の殆どがstandby query scn advanceですね。

プライマリでのデータ更新が適用されてからスタンバイ側のクエリSCNが更新されるので、スタンバイでクエリを実行するとstandby query scn advance待機が発生するという訳です。

尚、この環境では同一サーバ上にプライマリ・スタンバイ双方のDBが存在するのでプライマリースタンバイ間の通信にかかる時間はわずかで、リアルタイム適用が有効となっているのでプライマリ側の処理はすぐにスタンバイ側に反映されます。

逆の場合は上記のstandby query scn advance待機が発生する分、余計に時間がかかってしまうようです。

 

次にロック競合が発生するDMLを実行してみました。

プライマリ側

SQL> delete from t1 where col1=2;
6 rows deleted.
Elapsed: 00:00:37.57

スタンバイ側

SQL> delete from t1 where col1=2;

ERROR at line 1:
ORA-02049: timeout: distributed transaction waiting for lock
ORA-02063: preceding line from ADGREDIRECT

ロックが獲得できず、エラーになってしまいました。

そこでスタンバイ側で発行したupdateで、プライマリ側でロックが取得されるのを確認してから、プライマリで実行してみました。

スタンバイ側

SQL> delete from t1 where col1=2;
6 rows deleted.
Elapsed: 00:00:47.36

プライマリ側

SQL> delete from t1 where col1=2;
6 rows deleted.
Elapsed: 00:01:05.33

スタンバイ側の遅い処理が終わるまで、ずっと待たされてしまいます。まあ、ロック競合しているのだから当然です。

プライマリ側で先にロック獲得した場合は、スタンバイ側は待機せずにエラーになるようです。

 

insertならば競合しないだろうという事で、insert select でテストしてみます。

プライマリ側

SQL> insert into t1(col1) select col2 from t2 where col1=1;

1000 rows created.

Elapsed: 00:00:00.67

スタンバイ側

SQL> insert into t1(col1) select col2 from t2 where col1=1;

1000 rows created.

Elapsed: 00:11:01.18

プライマリがで1秒もかからない処理で、スタンバイでは11分以上もかかってしまいました。

これはstandby query scn advanceでは説明付かなそうです。

一体、何に11分以上もかかっているのか・・・?

 

Active Data Guard DMLリダイレクトの検証(2)に続きます。

*1:マスタサイトとスナップショットサイトからなるレプリケーション環境で、スナップショット側でも更新が可能な設定