Creating a Logical Standby Database

Como um dos pré-requisitos do Logical Standby é criá-lo a partir do Physical Standby, fiz um clone das máquinas que utilizei NESTE artigo, para investir melhor o tempo.

Confirmando que o primary está disponível:

[oracle@fornix1 ~]$ srvctl status database -d cortex
Database is running.

Checando o (até então) Physical Standby:

[oracle@fornix2 ~]$ srvctl status database -d cortexdr
Database is running.

Habilitando replicação entre os bancos:

[oracle@fornix2 ~]$ sqlplus / as sysdba
 
SQL*Plus: Release 19.0.0.0.0 - Production on Sat Mar 13 15:53:09 2021
Version 19.3.0.0.0
 
Copyright (c) 1982, 2019, Oracle.  All rights reserved.
 
 
Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0
 
SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE DISCONNECT;
 
Database altered.

O Logical Standby possui algumas limitações de replicação que devem ser mapeadas antes de efetivamente ser criado. No banco Primary, é possível acessar a lista de objetos que não sejam suportados. No meu caso, como é um banco de laboratório, não há nada efetivamente rodando nele, e consequentemente nenhum objeto que não seja suportado:

[oracle@fornix1 ~]$ sqlplus / as sysdba
 
SQL*Plus: Release 19.0.0.0.0 - Production on Sat Mar 13 15:56:21 2021
Version 19.3.0.0.0
 
Copyright (c) 1982, 2019, Oracle.  All rights reserved.
 
 
Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0
 
SQL> set pagesize 25
SQL> column owner format a5
SQL> SELECT DISTINCT OWNER, TABLE_NAME FROM DBA_LOGSTDBY_UNSUPPORTED ORDER BY OWNER,TABLE_NAME;
 
no rows selected

Criando uma tabela de teste:

SQL> CREATE TABLE SOE.BSS (COLUNA BFILE);
 
Table created.

Realizando consulta novamente:

SQL> set pagesize 25
SQL> column owner format a5
SQL> SELECT DISTINCT OWNER, TABLE_NAME FROM DBA_LOGSTDBY_UNSUPPORTED ORDER BY OWNER,TABLE_NAME;
 
OWNER
-----
TABLE_NAME
--------------------------------------------------------------------------------
SOE
BSS

Neste caso, podemos ver mais detalhes sobre a limitação, utilizando o comando abaixo:

SQL> SELECT COLUMN_NAME,DATA_TYPE FROM DBA_LOGSTDBY_UNSUPPORTED WHERE OWNER='SOE' AND TABLE_NAME= 'BSS';
 
COLUMN_NAME
--------------------------------------------------------------------------------
DATA_TYPE
--------------------------------------------------------------------------------
COLUNA
BFILE

O script abaixo também nos reporta as tabelas que possuem alguma limitações por datatype de colunas:

SQL> SELECT * FROM LOGSTDBY_UNSUPPORTED_TABLES;
 
OWNER
-----
TABLE_NAME
--------------------------------------------------------------------------------
SOE
BSS

Outra característica do Logical Standby, é que o mesmo não suporta schemas classificados como internos, vide exemplo abaixo:

SQL> SET PAGES 100
SQL> column owner format a25
SQL> SELECT OWNER FROM DBA_LOGSTDBY_SKIP WHERE STATEMENT_OPT = 'INTERNAL SCHEMA' ORDER BY 1;
 
OWNER
-------------------------
ANONYMOUS
APPQOSSYS
AUDSYS
CTXSYS
DBSFWUSER
DBSNMP
DIP
DVF
DVSYS
GGSYS
GSMADMIN_INTERNAL
GSMCATUSER
GSMROOTUSER
GSMUSER
LBACSYS
MDSYS
OJVMSYS
OLAPSYS
ORACLE_OCM
ORDDATA
ORDPLUGINS
ORDSYS
OUTLN
REMOTE_SCHEDULER_AGENT
SI_INFORMTN_SCHEMA
SYS
SYS$UMF
SYSBACKUP
SYSDG
SYSKM
SYSRAC
SYSTEM
WMSYS
XDB
XS$NULL
 
35 rows selected.

Tabelas que não tenham identificador único também não são suportadas pelo Logical, e podem ser encontradas na consulta abaixo:

SQL> COL OWNER FORMAT A30
SQL> COL TABLE_NAME FORMAT A80
SQL> SELECT OWNER, TABLE_NAME,BAD_COLUMN FROM DBA_LOGSTDBY_NOT_UNIQUE ;
 
OWNER                          TABLE_NAME                                                                       B
------------------------------ -------------------------------------------------------------------------------- -
SOE                            WAREHOUSES                                                                       N
SOE                            LOGON                                                                            N
SOE                            PRODUCT_DESCRIPTIONS                                                             N
SOE                            ORDERENTRY_METADATA                                                              N

Todos os objetos que são expostos nas consultas dos passos acima devem ser tratados e avaliados, para que a criação do Logical Standby seja saudável, e logicamente, não trazer problemas futuro ao ambiente. Agora vamos efetivamente à construção do Logical:

Parando o Redo Apply no Standby:

SQL> ALTER SYSTEM SWITCH LOGFILE;
 
System altered.
 
SQL> !hostname
fornix1
SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE CANCEL;
 
Database altered.
 
SQL> !hostname
fornix2

No ambiente primary, precisamos rodar o comando abaixo para a criação do LogMiner Dictionary:

SQL> execute DBMS_LOGSTDBY.BUILD;
 
PL/SQL procedure successfully completed.

É recomandado também aumentar a retenção de UNDO em ambos ambientes:

SQL> SELECT INSTANCE_NAME,STATUS FROM V$INSTANCE;
 
INSTANCE_NAME    STATUS
---------------- ------------
cortex           OPEN
 
SQL> show parameter UNDO_RETENTION
 
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
undo_retention                       integer     900
SQL> alter system set UNDO_RETENTION=3600 scope=both;
 
System altered.
SQL> SELECT INSTANCE_NAME,STATUS FROM V$INSTANCE;
 
INSTANCE_NAME    STATUS
---------------- ------------
CORTEXDR         MOUNTED
 
SQL> show parameter UNDO_RETENTION
 
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
undo_retention                       integer     900
SQL> alter system set UNDO_RETENTION=3600 scope=both;
 
System altered.

Convertendo o Physical Standby para Logical Standby:

SQL> SHU IMMEDIATE;
ORA-01109: database not open
 
 
Database dismounted.
ORACLE instance shut down.
SQL> STARTUP MOUNT EXCLUSIVE;
ORACLE instance started.
 
Total System Global Area 2583690520 bytes
Fixed Size                  8899864 bytes
Variable Size             553648128 bytes
Database Buffers         2013265920 bytes
Redo Buffers                7876608 bytes
Database mounted.
SQL> ALTER DATABASE RECOVER TO LOGICAL STANDBY CORTEXDR;
 
Database altered.

Baixando o standby e abrindo-o com resetlogs, além de iniciar o serviço de SQL apply:

SQL> SHU IMMEDIATE;
ORA-01507: database not mounted


ORACLE instance shut down.
SQL> STARTUP MOUNT;
ORACLE instance started.

Total System Global Area 2583690520 bytes
Fixed Size                  8899864 bytes
Variable Size             553648128 bytes
Database Buffers         2013265920 bytes
Redo Buffers                7876608 bytes
Database mounted.
SQL> ALTER DATABASE OPEN RESETLOGS;

Database altered.

SQL> ALTER DATABASE START LOGICAL STANDBY APPLY IMMEDIATE;

Database altered.

Validando os status dos Online Redo Logs no standby:

SQL> SELECT THREAD#, SEQUENCE#, ARCHIVED, STATUS FROM V$LOG;
 
   THREAD#  SEQUENCE# ARC STATUS
---------- ---------- --- ----------------
         1          1 NO  CURRENT
         1          0 YES UNUSED
         1          0 YES UNUSED

Para validar a replicação, vou criar uma tabela nova com 1 registro no primary:

SQL> CREATE TABLE SOE.BSS1 (NOME VARCHAR2(50));
 
Table created.
 
SQL> ALTER TABLE SOE.BSS1 ADD PRIMARY KEY (NOME);
 
SQL> INSERT INTO SOE.BSS1 (NOME) VALUES ('BRUNO');
 
1 row created.
 
SQL> COMMIT;
 
Commit complete.
 
SQL> ALTER SYSTEM SWITCH LOGFILE;
 
System altered.

Checando o Logical Standby:

SQL> DESC SOE.BSS1;
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 NOME                                      NOT NULL VARCHAR2(50)
 
SQL> SELECT * FROM SOE.BSS1;
 
NOME
--------------------------------------------------
BRUNO

Por último, precisamos ajustar o atributo VALID_FOR dos 2 bancos, para que já fiquem configurados quando um switchover ocorrer.

Criando diretório de destino dos archived redo log files do standby redo logs:

ASMCMD> pwd
+DG_RECO/CORTEX/ARCHIVELOG
ASMCMD> !hostname
fornix1
ASMCMD> mkdir ARCHREDOLOG
ASMCMD> ls ARCHREDOLOG

Alterando parâmetros do primary:

[oracle@fornix1 ~]$ sqlplus / as sysdba
 
SQL*Plus: Release 19.0.0.0.0 - Production on Sun Mar 14 04:54:44 2021
Version 19.3.0.0.0
 
Copyright (c) 1982, 2019, Oracle.  All rights reserved.
 
 
Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0
 
SQL> show parameter LOG_ARCHIVE_DEST_1
 
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
log_archive_dest_1                   string      LOCATION=+DG_RECO
log_archive_dest_10                  string
log_archive_dest_11                  string
log_archive_dest_12                  string
log_archive_dest_13                  string
log_archive_dest_14                  string
log_archive_dest_15                  string
log_archive_dest_16                  string
log_archive_dest_17                  string
log_archive_dest_18                  string
log_archive_dest_19                  string
SQL> ALTER SYSTEM SET LOG_ARCHIVE_DEST_1='LOCATION=+DG_RECO VALID_FOR=( ONLINE_LOGFILES,ALL_ROLES) DB_UNIQUE_NAME=CORTEX' scope=both;
 
System altered.
 
SQL> show parameter LOG_ARCHIVE_DEST_2
 
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
log_archive_dest_2                   string      SERVICE=cortexDR ASYNC VALID_F
                                                 OR=(ONLINE_LOGFILES,PRIMARY_RO
                                                 LE) DB_UNIQUE_NAME=cortexDR
log_archive_dest_20                  string
log_archive_dest_21                  string
log_archive_dest_22                  string
log_archive_dest_23                  string
log_archive_dest_24                  string
log_archive_dest_25                  string
log_archive_dest_26                  string
log_archive_dest_27                  string
 
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
log_archive_dest_28                  string
log_archive_dest_29                  string
SQL> ALTER SYSTEM SET LOG_ARCHIVE_DEST_3='LOCATION=+DG_RECO/CORTEX/ARCHIVELOG/ARCHREDOLOG/ VALID_FOR=(STANDBY_LOGFILES,STANDBY_ROLE) DB_UNIQUE_NAME=CORTEX' scope=both;
 
System altered.
 
SQL> ALTER SYSTEM SET LOG_ARCHIVE_DEST_STATE_3=ENABLE;
 
System altered.

Criando diretório no Standby:

ASMCMD> !hostname
fornix2
ASMCMD> pwd
+DG_RECO/CORTEXDR/ARCHIVELOG
ASMCMD> mkdir ARCHREDOLOG

Alterando parâmetros no standby:

[oracle@fornix2 ~]$ sqlplus / as sysdba
 
SQL*Plus: Release 19.0.0.0.0 - Production on Sun Mar 14 05:04:25 2021
Version 19.3.0.0.0
 
Copyright (c) 1982, 2019, Oracle.  All rights reserved.
 
 
Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0
 
SQL> show parameter LOG_ARCHIVE_DEST_1;
 
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
log_archive_dest_1                   string      LOCATION=+DG_RECO
log_archive_dest_10                  string
log_archive_dest_11                  string
log_archive_dest_12                  string
log_archive_dest_13                  string
log_archive_dest_14                  string
log_archive_dest_15                  string
log_archive_dest_16                  string
log_archive_dest_17                  string
log_archive_dest_18                  string
log_archive_dest_19                  string
SQL> ALTER SYSTEM SET LOG_ARCHIVE_DEST_1='LOCATION=+DG_RECO VALID_FOR=( ONLINE_LOGFILES,ALL_ROLES) DB_UNIQUE_NAME=CORTEXDR' scope=both;
 
System altered.
 
SQL> show parameter LOG_ARCHIVE_DEST_2;
 
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
log_archive_dest_2                   string      SERVICE=CORTEX ASYNC DB_UNIQUE
                                                 _NAME=cortex VALID_FOR=(ONLINE
                                                 _LOGFILE,PRIMARY_ROLE)
log_archive_dest_20                  string
log_archive_dest_21                  string
log_archive_dest_22                  string
log_archive_dest_23                  string
log_archive_dest_24                  string
log_archive_dest_25                  string
log_archive_dest_26                  string
log_archive_dest_27                  string
 
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
log_archive_dest_28                  string
log_archive_dest_29                  string
SQL> ALTER SYSTEM SET LOG_ARCHIVE_DEST_2= 'SERVICE=CORTEX ASYNC NOAFFIRM delay=0 reopen=300 VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE) DB_UNIQUE_NAME=CORTEX' SCOPE=BOTH ;
 
System altered.
 
SQL> ALTER SYSTEM SET LOG_ARCHIVE_DEST_STATE_2=ENABLE;
 
System altered.
 
SQL> ALTER SYSTEM SET LOG_ARCHIVE_DEST_3='LOCATION=+DG_RECO/CORTEXDR/ARCHIVELOG/ARCHREDOLOG/ VALID_FOR=(STANDBY_LOGFILES,STANDBY_ROLE) DB_UNIQUE_NAME=CORTEXDR' scope=both;
 
System altered.
 
SQL> ALTER SYSTEM SET LOG_ARCHIVE_DEST_STATE_3=ENABLE;
 
System altered.
 
SQL>

E finalmente, caso queiramos parar o serviço de replicação, basta rodar o comando abaixo no standby:

SQL> ALTER DATABASE STOP LOGICAL STANDBY APPLY;
 
Database altered.

Obs: Este procedimento foi criado pelo senhor Ahmed Baraka (www.ahmedbaraka.com) e foi apenas reproduzido por mim em um laboratório pessoal para fins de aprendizado.

Leave a Comment

Your email address will not be published.