Possível Bug na migração do Oracle Database 12.2 de nonCDB para PDB

Olá pessoal, aqui vai um breve artigo sobre um possível bug que encontrei na migração do Oracle Database 12.2 de nonCDB para PDB. É um problema contornável e aqui também apresento a solução.

Após reportar para o Mike Dietrich (Master Product Manager – Database Upgrades & Migrations), ele levantou a questão junto ao responsável pelo script noncdb_to_pdb.sql e caso necessário será aberto um bug para o caso.

Cenário que encontrei

Para este cenário segui exatamente o artigo do Tim Hall: https://oracle-base.com/articles/12c/multitenant-hot-clone-remote-pdb-or-non-cdb-12cr2

O problema que tive foi por conta de um parâmetro estar com um valor menor do que o Oracle esperava. Vamos ver o que aconteceu…

O objetivo era migrar o banco de dados de nome noncdb1 que estava na versão 12.2.0.1 para um PDB no banco de dados de nome cdb3 também na versão 12.2.0.1.

Depois de configurar o ambiente conforme o artigo do Tim Hall executei os seguintes passos apresentados abaixo…

No banco de dados cdb3:

SQL> CREATE PLUGGABLE DATABASE pdb4 FROM NON$CDB@clone_link;

Pluggable database created.

Meu PDB pdb4 foi criado com sucesso a partir do banco de dados noncdb1. Vamos ver o status dos PDBs:

SQL> column name format a30
SELECT
    d.con_id,
    p.name,
    p.open_mode,
    d.status,
    TO_CHAR(
        p.open_time,
        'DD/MM/YYYY HH24:MI:SS'
    ) open_time,
    p.total_size / 1024 / 1024 total_mb,
    p.max_size / 1024 / 1024 max_mb,
    p.local_undo,
    d.refresh_mode
FROM
    v$pdbs p,
    dba_pdbs d
WHERE
    p.name = d.pdb_name
ORDER BY 1;

    CON_ID NAME 			  OPEN_MODE  STATUS	    OPEN_TIME	          TOTAL_MB	   MAX_MB LOCAL_UNDO REFRES
---------- ------------------ ---------- ---------- ------------------- ---------- ---------- ---------- ------
	     2 PDB$SEED			  READ ONLY  NORMAL	    28/06/2017 21:51:04	       744		    0	       1 NONE
	     3 PDB1 			  MOUNTED    NORMAL	    			                 0		    0	       1 NONE
	     4 PDB4 			  MOUNTED    NEW	    28/06/2017 22:08:54	         0		    0	       1 NONE
	     5 PDB2 			  READ WRITE NORMAL	    28/06/2017 21:51:05	      3537		    0	       1 NONE
	     6 PDB3 			  READ WRITE NORMAL	    28/06/2017 21:51:05	      3902		    0	       1 NONE

Elapsed: 00:00:00.02

Feito isso direcionei a sessão para o novo pdb4:

SQL> alter session set container=pdb4;

Session altered.

Elapsed: 00:00:00.00

Como já sei do problema verifico o parâmetro job_queue_processes:

SQL> sho parameter job_queue

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
job_queue_processes                  integer     4000

Vejam que o job_queue_processes está definido com o valor de 4000 para o meu PDB.

Então executei o script de conversão de nonCDB para PDB nesta mesma sessão:

SQL> @?/rdbms/admin/noncdb_to_pdb.sql

--...MUITAS LINHAS DE EXECUÇÃO NÃO APRESENTADAS AQUI POR NÃO INFLUENCIAREM NO CONTEXTO APRESENTADO

22:28:29 DOC>#
22:28:29 SQL>
22:28:29 SQL> DECLARE
22:28:29 2 threads pls_integer := &&1;
22:28:29 3 BEGIN
22:28:29 4 utl_recomp.recomp_parallel(threads);
22:28:29 5 END;
22:28:29 6 /
DECLARE
*
ERROR at line 1:
ORA-20000: Unable to gather statistics concurrently: the job_queue_processes
parameter is less than 4
ORA-06512: at "SYS.UTL_RECOMP", line 899
ORA-06512: at "SYS.DBMS_STATS", line 36873
ORA-06512: at "SYS.DBMS_STATS", line 4298
ORA-06512: at "SYS.DBMS_STATS", line 36652
ORA-06512: at "SYS.UTL_RECOMP", line 260
ORA-06512: at "SYS.UTL_RECOMP", line 803
ORA-06512: at line 4

Disconnected from Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
[oracle@oracle-srv ~]$

Observem que o erro retornado no script, após um bom tempo de execução, é referente ao parâmetro estar definido com um valor abaixo de 4, porém conferimos que o parâmetro estava em 4000 antes de executarmos o script. Este erro acontece na etapa de compilação de objetos onde o Oracle tenta executar com paralelismo de 4 e não consegue devido ao valor do parâmetro estar abaixo, mas acredito que isso seja um problema do script, pois não acho que ele deveria esperar um valor exato e ainda assim verificamos que o parâmetro job_queue_processes do pdb4 estava em 4000 antes da execução.

Ao verificar o meu banco de dados noncdb que foi copiado e então convertido nesta migração identifiquei que nele o valor definido para o parâmetro job_queue_processes era 3:

[oracle@oracle-srv ~]$ . oraenv
ORACLE_SID = [cdb2] ? noncdb1
The Oracle base remains unchanged with value /u01/app/oracle
[oracle@oracle-srv ~]$ sqlplus / as sysdba

SQL*Plus: Release 12.2.0.1.0 Production on Wed Jun 28 22:25:18 2017

Copyright (c) 1982, 2016, Oracle. All rights reserved.

Connected to:
Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production

SQL> sho parameter db_name

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
db_name                              string      noncdb1

SQL> sho parameter job_queue

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
job_queue_processes                  integer     3

Então em algum momento o Oracle grava o parâmetro antigo e tenta reutilizar nesta conversão.

Para corrigir não é necessário alterar o parâmetro no banco de dados nonCDB e copiá-lo novamente. Vamos ver como resolver depois de migrado.

Vamos ver como o pdb4 ficou agora depois da execução com erro do script:

SQL> column name format a30
SELECT
    d.con_id,
    p.name,
    p.open_mode,
    d.status,
    TO_CHAR(
        p.open_time,
        'DD/MM/YYYY HH24:MI:SS'
    ) open_time,
    p.total_size / 1024 / 1024 total_mb,
    p.max_size / 1024 / 1024 max_mb,
    p.local_undo,
    d.refresh_mode
FROM
    v$pdbs p,
    dba_pdbs d
WHERE
    p.name = d.pdb_name
ORDER BY 1;

    CON_ID NAME 			              OPEN_MODE  STATUS	    OPEN_TIME	          TOTAL_MB     MAX_MB LOCAL_UNDO REFRES
---------- ------------------------------ ---------- ---------- ------------------- ---------- ---------- ---------- ------
	     2 PDB$SEED			              READ ONLY  NORMAL	    28/06/2017 21:51:04	       744		    0	       1 NONE
	     3 PDB1 			              MOUNTED    NORMAL	    			                 0		    0	       1 NONE
	     4 PDB4 			              READ WRITE NEW	    28/06/2017 22:28:18	      3000		    0	       1 NONE
	     5 PDB2 			              READ WRITE NORMAL	    28/06/2017 21:51:05	      3537		    0	       1 NONE
	     6 PDB3 			              READ WRITE NORMAL	    28/06/2017 21:51:05	      3902		    0	       1 NONE

Elapsed: 00:00:00.02

Vejam que o pdb4 está em modo read write, isso porque durante a execução do script o mesmo executa um “open upgrade” no PDB.

Vamos ver como está o parâmetro:

SQL> alter session set container=pdb4;

Session altered.

Elapsed: 00:00:00.05

SQL> sho parameter job_queue

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
job_queue_processes                  integer     3

O parâmetro agora está definido com o valor 3. Vamos alterar para 4 e baixar o pdb4 deixando-o em modo mount:

SQL> alter system set job_queue_processes=4;

System altered.

Elapsed: 00:00:00.03

SQL> alter pluggable database close;

Pluggable database altered.

Elapsed: 00:00:01.74

Agora reexecutamos o script noncdb_to_pdb.sql:

SQL> show con_name

CON_NAME
------------------------------
PDB4

SQL> @?/rdbms/admin/noncdb_to_pdb.sql
-- MUITAS LINHAS AQUI, MAS O SCRIPT FINALIZA SEM ERROS...

Desta vez ele finaliza com sucesso, sem erros.

Vamos então abrir o pdb4 e finalizar o processo de migração de nonCDB para PDB:

SQL> sho con_name

CON_NAME
------------------------------
PDB4

SQL> select open_mode from v$pdbs;

OPEN_MODE
----------
MOUNTED

1 row selected.

Elapsed: 00:00:00.01

SQL> alter pluggable database open;

Pluggable database altered.

Elapsed: 00:00:11.49

PDB aberto com sucesso.

Na view PDB_PLUG_IN_VIOLATIONS podemos verificar que o erro na execução do script noncdb_to_pdb.sql está com o status “RESOLVED”, mas ainda temos um warning que é referente aos serviços que existian no banco de dados noncdb1:

SQL> select * from PDB_PLUG_IN_VIOLATIONS;

TIME                           NAME  CAUSE                          TYPE      ERROR_NUMBER       LINE MESSAGE                                            STATUS    ACTION                             CON_ID
------------------------------ ----- ------------------------------ --------- ------------ ---------- -------------------------------------------------- --------- ------------------------------ ----------
28-JUN-17 11.00.36.534704 PM   PDB4  Non-CDB to PDB                 ERROR                0          1 PDB plugged in is a non-CDB, requires noncdb_to_pd RESOLVED  Run noncdb_to_pdb.sql.                  4
                                                                                                      b.sql be run.

28-JUN-17 11.00.36.760384 PM   PDB4  Service Name Conflict          WARNING              0          1 Service name or network name of service noncdb1XDB in PENDING   Drop the service and recreate         4
                                                                                                       the PDB is invalid or conflicts with an existing            it with an appropriate name.
                                                                                                      service name or network name in the CDB.


2 rows selected.

Elapsed: 00:00:00.00

Para remover estes serviços podemos consultar:

SQL> select name from dba_services;

NAME
------------------------------
noncdb1XDB
noncdb1
pdb4.localdomain

3 rows selected.

Elapsed: 00:00:00.00

Como estamos conectados no pdb4, não deve haver serviços chamados ‘%cdb%’. Vamos então removê-los:

SQL> exec dbms_service.delete_service('noncdb1XDB');

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.06

SQL> exec dbms_service.delete_service('noncdb1');

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.01

E então reinicio novamente o pdb4 para verificar o novo status da view PDB_PLUG_IN_VIOLATIONS:

SQL> alter pluggable database close;

Pluggable database altered.

Elapsed: 00:00:00.41

SQL>  alter pluggable database open;

Pluggable database altered.

Elapsed: 00:00:01.40

Consulto novamente a view e identifico que os erros e alertas estão todos resolvidos:

SQL> select * from PDB_PLUG_IN_VIOLATIONS;

TIME                           NAME                           CAUSE                          TYPE      ERROR_NUMBER       LINE MESSAGE                                            STATUS    ACTION                             CON_ID
------------------------------ ------------------------------ ------------------------------ --------- ------------ ---------- -------------------------------------------------- --------- ------------------------------ ----------
28-JUN-17 11.00.36.534704 PM   PDB4                           Non-CDB to PDB                 ERROR                0          1 PDB plugged in is a non-CDB, requires noncdb_to_pd RESOLVED  Run noncdb_to_pdb.sql.                  4
                                                                                                                               b.sql be run.

28-JUN-17 11.08.37.826200 PM   PDB4                           Service Name Conflict          WARNING              0          1 Service name or network name of service noncdb1XDB in RESOLVED  Drop the service and recreate         4
                                                                                                                                the PDB is invalid or conflicts with an existing            it with an appropriate name.
                                                                                                                               service name or network name in the CDB.


2 rows selected.

Elapsed: 00:00:00.02

Solução de contorno proposta pelo Mike

Depois de falar com o Mike Dietrich ele testou diversas vezes e informou outra solução de contorno: desabiltar as estatísticas concorrentes no PDB em questão.

Para desabilitar execute:

SQL> EXEC DBMS_STATS.SET_GLOBAL_PREFS('CONCURRENT','FALSE');

PL/SQL procedure successfully completed.

bug na migração Oracle 12.2

Bom pessoal, por hoje é isso. Espero que ajude quando tiverem que fazer este tipo de migração.

Abraços,

Franky