Para melhor visualização, recomendo resolução de no mínimo 1024 x 768 e navegadores Mozilla Firefox ou Google Chrome


segunda-feira, 4 de agosto de 2014

Oracle Multitenant: Alterando parâmetros de inicialização do Container Database (CDB) e Pluggable Databases (PDBs) no Oracle 12c

Por Eduardo Legatti

Olá,

Nos artigos de Fevereiro/2014, Março/2014 e Abril/2014 e abordei sobre a arquitetura Multitenant do Oracle 12c no que se refere aos conceitos básicos de administração e de backups dos containers (CDBs) e dos bancos de dados plugáveis (PDBs). Neste artigo irei demonstrar de forma prática a alteração dos parâmetros da instância container (CDB) e dos bancos de dados plugáveis (PDBs).

Para começar, é importante frisar que só existe um arquivo de inicialização SPFILE para a instância CDB. Isso quer dizer que não existe um arquivo de inicialização SPFILE separado para os bancos de dados plugáveis (PDBs). Neste caso, todos os bancos de dados PDBs herdam os valores dos parâmetros do banco de dados CDB. Alguns parâmetros dos bancos de dados PDBs podem ser alterados, outros não. o valor da coluna ISPDB_MODIFIABLE da view V$SYSTEM_PARAMETER irá nos informar se o parâmetro em questão poderá ser modificado. Segue a demonstração abaixo.
 
C:\>set ORACLE_SID=CDB01

C:\>sqlplus / as sysdba

SQL*Plus: Release 12.1.0.1.0 Production on Seg Ago 4 09:43:13 2014

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

Conectado a:
Oracle Database 12c Enterprise Edition Release 12.1.0.1.0 - 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options

SQL> show con_name;

CON_NAME
-----------------------
CDB$ROOT

SQL> select a.con_id,a.name,a.dbid,
  2         b.status,a.open_mode,a.total_size
  3    from v$pdbs a, dba_pdbs b
  4   where a.con_id=b.pdb_id;

    CON_ID NAME                    DBID STATUS        OPEN_MODE  TOTAL_SIZE
---------- ----------------- ---------- ------------- ---------- ----------
         2 PDB$SEED          4076210644 NORMAL        READ ONLY   283115520
         3 PDB01             3898013363 NORMAL        READ WRITE  288358400
         4 PDB02             3947824578 NORMAL        READ WRITE  283115520
         5 PDB03             4001514065 NORMAL        READ WRITE  288358400

SQL> show parameter spfile;

NAME      TYPE        VALUE
--------- ----------- --------------------------------------------------------------
spfile    string      C:\ORACLE\APP\PRODUCT\12.1.0\DBHOME_1\DATABASE\SPFILECDB01.ORA

Acima podemos verificar que a instância CDB foi aberta com o parâmetro de inicialização SPFILECDB01.ORA e que 3 bancos de dados PDBs estão abertos. Abaixo irei alterar o parâmetro "open_cursors" banco de dados de container CDB$ROOT.
 
SQL> alter system set open_cursors=210;

Sistema alterado.

O comando ALTER SYSTEM acima modificou o parâmetro "open_cursors" tanto em memória quanto no arquivo SPFILE. No Oracle 12c foi incluído uma nova cláusula no comando ALTER SYSTEM que indica se a alteração realizada no parâmetro deverá afetar apenas o banco de dados de container atual (CURRENT) ou em todos os containers (ALL). Se o mesmo não for especificado, então o padrão será CURRENT.
 
SQL> show parameter open_cursors;

NAME                            TYPE        VALUE
------------------------------- ----------- ---------------------------
open_cursors                    integer     210

SQL> select name,value,display_value,ispdb_modifiable
  2    from v$system_parameter
  3   where name = 'open_cursors';

NAME            VALUE      DISPLAY_VA ISPDB
--------------- ---------- ---------- -----
open_cursors    210        210        TRUE

Acima podemos verificar que o parâmetro "open_cursors" foi alterado no banco de dados de container CDB$ROOT e que o mesmo pode ser modificado também nos bancos de dados plugáveis. Irei realizar abaixo a alteração no banco de dados plugável PDB01.
 
SQL> alter session set container = PDB01;

Sessão alterada.

SQL> show con_name;

CON_NAME
------------------------------
PDB01

SQL> alter system set open_cursors=220;

Sistema alterado.

SQL> select name,value,display_value,ispdb_modifiable
  2    from v$system_parameter
  3   where name = 'open_cursors';

NAME            VALUE      DISPLAY_VA ISPDB
--------------- ---------- ---------- -----
open_cursors    220        220        TRUE

Após a alteração do parâmetro no banco de dados plugável PDB01, irei conectar novamente no container CDB$ROOT e consultar a view V$SYSTEM_PARAMETER.
 
SQL> alter session set container = CDB$ROOT;

Sessão alterada.

SQL> select name,value,display_value,con_id,ispdb_modifiable
  2    from v$system_parameter
  3   where name = 'open_cursors';

NAME           VALUE      DISPLAY_VA     CON_ID ISPDB
-------------- ---------- ---------- ---------- -----
open_cursors   210        210                 0 TRUE
open_cursors   220        220                 3 TRUE

O resultado acima demonstra que é possível consultar os valores dos parâmetros dos banco de dados plugáveis que tiveram seus valores alterados à partir do container CDB$ROOT. Vale a pena salientar que o banco de dados plugável precisa estar aberto para que a consulta retorne os valores dos parâmetros. Bom, após a alteração do parâmetro "open_cursors" tanto no container CDB quanto no banco de dados PDB01, segue abaixo o conteúdo o SPFILE após o mesmo ser convertido para PFILE.
 
C:\>type INITcdb01.ORA

cdb01.__data_transfer_cache_size=0
cdb01.__db_cache_size=729808896
cdb01.__java_pool_size=4194304
cdb01.__large_pool_size=12582912
cdb01.__oracle_base='C:\oracle\app'
cdb01.__pga_aggregate_target=314572800
cdb01.__sga_target=1073741824
cdb01.__shared_io_pool_size=50331648
cdb01.__shared_pool_size=264241152
cdb01.__streams_pool_size=0
*.audit_file_dest='C:\oracle\app\admin\CDB01\adump'
*.audit_trail='db'
*.compatible='12.1.0.0.0'
*.control_files='C:\oracle\CDB01\control01.ctl','C:\oracle\CDB01\control02.ctl'
*.db_block_size=8192
*.db_domain=''
*.db_name='CDB01'
*.db_recovery_file_dest_size=53687091200
*.db_recovery_file_dest='C:\oracle\app\fast_recovery_area'
*.diagnostic_dest='C:\oracle\app'
*.dispatchers='(PROTOCOL=TCP) (SERVICE=CDB01XDB)'
*.enable_pluggable_database=true
*.nls_language='BRAZILIAN PORTUGUESE'
*.nls_territory='BRAZIL'
*.open_cursors=210
*.pga_aggregate_target=300m
*.processes=300
*.remote_login_passwordfile='EXCLUSIVE'
*.sga_target=1024m
*.undo_tablespace='UNDOTBS1'

Verificando o resultado acima é possível perceber que apenas o valor do parâmetro "open_cursors" do container CDB01 se encontra armazenado no SPFILE. Portanto, é possível concluir que os valores dos parâmetros dos bancos de dados PDBs não ficam armazenados no arquivo de inicialização SPFILE e sim nas tabelas de dicionário de dados do banco de dados de container CDB$ROOT como demonstrado pela consulta SQL abaixo. Com ela é possível obter os valores do parâmetros de inicialização dos bancos de dados plugáveis consultando a tabela de dicionário de dados PDB_SPFILE$:
 
SQL> select a.name,value$,con_id 
  2    from pdb_spfile$ a 
  3    join v$pdbs b on (a.pdb_uid=b.con_uid);

NAME                 VALUE$         CON_ID
-------------------- ---------- ----------
open_cursors         220                 3
 

terça-feira, 1 de julho de 2014

Configurando um Script Master para execução de scripts no SQL*Plus

Por Eduardo Legatti

Olá,

Quando precisamos executar vários scripts SQL em um banco de dados, geralmente automatizamos a sua execução para não ter que ficarmos executando script por script. Dependendo do ambiente, como no caso de um banco de produção, a boa prática é colher todas as informações da execução realizada afim de se ter uma evidência ou prova do que foi executado. Portanto, um arquivo de log contendo as informações da execuções dos scripts é fundamental. Dentre as informações que eu considero importante que se tenha no arquivo de log, eu posso citar a instrução SQL que foi executada, o nome do script, a hora da execução, o tempo de execução, o nome do servidor e o nome do banco de dados. Neste artigo irei compartilhar um modelo de script que utilizo com uma certa frequência que tem como objetivo chamar outros scripts e gerar uma evidência da execução realizada. Apesar do script que utilizo fazer mais validações, irei demonstrar apenas o que considero básico para um Script Master. Segue abaixo o conteúdo do mesmo na qual irei realizar a execução de 9 scripts.
 
C:\SQL>type 00-ScriptMaster.sql

WHENEVER OSERROR EXIT 1;
WHENEVER SQLERROR EXIT 1;
SET ECHO ON
SET DEFINE OFF
SET FEEDBACK ON
SET TIME ON
SET TIMING ON
SET APPINFO ON
SET SERVEROUTPUT ON SIZE 1000000
SPOOL 00-ScriptMaster.log
select host_name,instance_name from v$instance;
alter session set nls_territory='BRAZIL';
alter session set current_schema=SCOTT;
@01-script01.sql
@02-script02.sql
@03-script03.sql
@04-script04.sql
@05-script05.sql
@06-script06.sql
@07-script07.sql
@08-script08.sql
@09-script09.sql
spool off
quit;
 
Como demonstrado acima, o script 00-ScriptMaster.sql é o nome do Script Master. Em resumo, ele contém algumas validações como o uso das cláusulas WHENEVER nas duas primeiras linhas. Elas indicam que que se algum script não for encontrado ou se ocorrer algum erro na execução de algum script, a execução do Script Master será abortada. Na minha opinião esse comportamento é fundamental de forma a evitar que os scripts subsequentes sejam afetados por um erro ocasionado na execução de um script anterior. Dessa forma, um script que der algum problema poderá ser tratado pontualmente.

Outro ponto que acho importante se refere ao SET DEFINE OFF que impede que o caracter "&" seja tratado como "host variable" no SQL*Plus. Em relação ao horário de execução e o tempo de execução de cada instrução, SET TIME ON e SET TIMING ON são fundamentais. Na linha 8, o SET APPINFO ON é útil para fins de monitoramento porque o script em execução será visível na coluna MODULE da view dinâmica de desempenho V$SESSION. Portanto, mesmo que o Script Master esteja em execução no servidor de banco de dados, será possível acompanhar de outra máquina qual script está sendo executado no momento consultando a view V$SESSION. O SET SERVEROUTPUT ON é útil para mostrar resultados de códigos PL/SQL que utilizam o comando DBMS_OUTPUT.

Na linha 10, o comando SPOOL irá gerar o arquivo de log na qual darei o nome de 00-ScriptMaster.log. Para evitar qualquer problema com formatos de data, pontos decimais e de milhar, eu costumo forçar o NLS_TERRITORY como demonstrado na linha 12.

Para evitar qualquer problema em relação à falta de priviégios durante a execução dos scripts, eu prefiro executar o Script Master com um usuário DBA, como por exemplo o SYSTEM. Como a conexão é feita pelo SYSTEM, eu forço a sessão para o schema que será alvo da execução dos scripts (SCOTT) como demonstrado na linha 13. Caso o Script Master envolva a execução de scripts em mais de um schema, então vários "alter session set current_schema" poderão ser inseridos ao longo do Script Master. Por fim, as linhas que começam com @ são exatamente os scripts que serão executados conforme demonstrado abaixo:

C:\SQL>dir
 O volume na unidade C não tem nome.
 O Número de Série do Volume é 1C51-B278

 Pasta de C:\SQL

01/07/2014  15:27    [DIR]          .
01/07/2014  15:27    [DIR]          ..
01/07/2014  15:43               517 00-ScriptMaster.sql
01/07/2014  15:37               118 01-script01.sql
01/07/2014  15:13                20 02-script02.sql
01/07/2014  15:14                38 03-script03.sql
01/07/2014  15:48               103 04-script04.sql
01/07/2014  15:53               202 05-script05.sql
01/07/2014  15:15                36 06-script06.sql
01/07/2014  15:17                97 07-script07.sql
01/07/2014  15:17                37 08-script08.sql
01/07/2014  15:35               256 09-script09.sql
              10 arquivo(s)         1.424 bytes
               2 pasta(s)   102.755.786.752 bytes disponíveis

No mais, segue uma execução do Script Master na qual eu simulo um erro de execução do script 04-script04.sql. Neste caso, a execução do Script Master será abortada e a saída gravada no arquivo de log 00-ScriptMaster.log.

C:\SQL>sqlplus system/manager @00-ScriptMaster.sql

SQL*Plus: Release 11.2.0.1.0 Production on Ter Jul 1 15:47:12 2014

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

Conectado a:
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options

15:47:21 SQL> select host_name,instance_name from v$instance;

HOST_NAME                         INSTANCE_NAME
--------------------------------- -------------
server01                          BD01

1 linha selecionada.

Decorrido: 00:00:00.01
15:47:21 SQL> alter session set nls_territory='BRAZIL';

Sessão alterada.

Decorrido: 00:00:00.00
15:47:21 SQL> alter session set current_schema=SCOTT;

Sessão alterada.

Decorrido: 00:00:00.00
15:47:21 SQL> @01-script01.sql
15:47:21 SQL> create table t1 (id number);

Tabela criada.

Decorrido: 00:00:00.12
15:47:21 SQL> create table t2 (id number);

Tabela criada.

Decorrido: 00:00:00.03
15:47:21 SQL> create table t3 (id number);

Tabela criada.

Decorrido: 00:00:00.00
15:47:21 SQL> create table t4 (id number);

Tabela criada.

Decorrido: 00:00:00.00
15:47:21 SQL> @02-script02.sql
15:47:21 SQL> drop table t3 purge;

Tabela eliminada.

Decorrido: 00:00:00.02
15:47:22 SQL> @03-script03.sql
15:47:22 SQL> alter table t1 add nome varchar2(100);

Tabela alterada.

Decorrido: 00:00:00.08
15:47:22 SQL> @04-script04.sql
15:47:22 SQL> insert into t1 values (1);
insert into t1 values (1)
            *
ERRO na linha 1:
ORA-00947: não há valores suficientes
 
Enfim, segue abaixo o conteúdo do arquivo de log após uma execução completa do Script Master.

C:\SQL>sqlplus system/manager @00-ScriptMaster.sql
15:54:35 SQL> select host_name,instance_name from v$instance;

HOST_NAME                         INSTANCE_NAME
--------------------------------- ----------------
server01                          BD01

1 linha selecionada.

Decorrido: 00:00:00.00
15:54:35 SQL> alter session set nls_territory='BRAZIL';

Sessão alterada.

Decorrido: 00:00:00.00
15:54:35 SQL> alter session set current_schema=SCOTT;

Sessão alterada.

Decorrido: 00:00:00.00
15:54:35 SQL> @01-script01.sql
15:54:35 SQL> create table t1 (id number);

Tabela criada.

Decorrido: 00:00:00.06
15:54:35 SQL> create table t2 (id number);

Tabela criada.

Decorrido: 00:00:00.01
15:54:35 SQL> create table t3 (id number);

Tabela criada.

Decorrido: 00:00:00.00
15:54:35 SQL> create table t4 (id number);

Tabela criada.

Decorrido: 00:00:00.00
15:54:35 SQL> @02-script02.sql
15:54:35 SQL> drop table t3 purge;

Tabela eliminada.

Decorrido: 00:00:00.03
15:54:35 SQL> @03-script03.sql
15:54:35 SQL> alter table t1 add nome varchar2(100);

Tabela alterada.

Decorrido: 00:00:00.01
15:54:35 SQL> @04-script04.sql
15:54:35 SQL> insert into t1 values (1,'x');

1 linha criada.

Decorrido: 00:00:00.04
15:54:35 SQL> insert into t1 values (2,'y');

1 linha criada.

Decorrido: 00:00:00.01
15:54:35 SQL> insert into t1 values (3,'z');

1 linha criada.

Decorrido: 00:00:00.01
15:54:35 SQL> commit;

Commit concluído.

Decorrido: 00:00:00.01
15:54:36 SQL> @05-script05.sql
15:54:36 SQL> insert into t2 values (10);

1 linha criada.

Decorrido: 00:00:00.01
15:54:36 SQL> commit;

Commit concluído.

Decorrido: 00:00:00.01
15:54:36 SQL> 
15:54:36 SQL> declare
15:54:36   2    tdata varchar2(8);
15:54:36   3  begin
15:54:36   4   select to_char(sysdate,'hh24:mi:ss') into tdata  from dual;
15:54:36   5   dbms_output.put_line(tdata);
15:54:36   6   dbms_lock.sleep(300);
15:54:36   7  end;
15:54:36   8  /
15:54:36

Procedimento PL/SQL concluído com sucesso.

Decorrido: 00:05:00.07
15:59:36 SQL> @06-script06.sql
15:59:36 SQL> create view v_1 as select * from t1;

View criada.

Decorrido: 00:00:00.07
15:59:36 SQL> @07-script07.sql
15:59:36 SQL> insert into t2 values (200);

1 linha criada.

Decorrido: 00:00:00.03
15:59:36 SQL> insert into t2 values (300);

1 linha criada.

Decorrido: 00:00:00.02
15:59:36 SQL> insert into t2 values (400);

1 linha criada.

Decorrido: 00:00:00.03
15:59:36 SQL> commit;

Commit concluído.

Decorrido: 00:00:00.03
15:59:36 SQL> @08-script08.sql
15:59:36 SQL> delete from t2 where id=200;

1 linha deletada.

Decorrido: 00:00:00.03
15:59:36 SQL> commit;

Commit concluído.

Decorrido: 00:00:00.05
15:59:36 SQL> @09-script09.sql
15:59:36 SQL> update t1 set id=id*10;

3 linhas atualizadas.

Decorrido: 00:00:00.06
15:59:36 SQL> commit;

Commit concluído.

Decorrido: 00:00:00.04
15:59:36 SQL> 
15:59:36 SQL> begin
15:59:36   2   for i in 1..10 loop
15:59:36   3     insert into t4 select level id from dual connect by level <=10;
15:59:36   4     if mod(i, 2) = 0 then
15:59:36   5        commit;
15:59:36   6        dbms_output.put_line('commit');
15:59:36   7     end if;
15:59:36   8   end loop;
15:59:36   9   commit;
15:59:36  10  end;
15:59:36  11  /
commit
commit
commit
commit
commit

Procedimento PL/SQL concluído com sucesso.

Decorrido: 00:00:00.12
15:59:37 SQL> spool off


Durante a execução do Script Master, foi possível identificar o script 05-script05.sql sendo executado consultado a view V$SESSION como demonstrado abaixo:

C:\>sqlplus system/manager

SQL*Plus: Release 11.2.0.1.0 Production on Ter Jul 1 15:55:04 2014

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

Conectado a:
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options

SQL> SELECT sid,serial#,username,schemaname,
  2  osuser,program,module
  3  FROM V$SESSION
  4  WHERE schemaname='SCOTT';

    SID  SERIAL# USERNAME     SCHEMANAME      OSUSER    PROGRAM      MODULE
------- -------- ------------ --------------- --------- ------------ -------------------
     68    53805 SYSTEM       SCOTT           legatti   sqlplus.exe  02@ 05-script05.sql

1 linha selecionada.

domingo, 1 de junho de 2014

Abordando o Table-Point-In-Time Recovery (TPITR) na prática com o RMAN do Oracle 12c

Por Eduardo Legatti

Olá,  

No artigo de Março/2010 eu abordei um pouco da técnica de recuperação pontual de dados já bem conhecida entre os DBAs Oracle chamada de Tablespace Point-in-Time Recovery (TSPITR) disponível desde a versão do Oracle 8 e também uma outra técnica chamada Database Point-in-Time Recovery (DBPITR). Como já explicado anteriormente naquele artigo, basicamente o TSPITR (Recuperação Pontual de Tablespace) é uma funcionalidade que fornece ao DBA a opção de recuperar um conjunto de dados em um ponto específico no tempo sem afetar o restante do banco de dados. Já o DBPITR possibilita um banco de dados inteiro "voltar no tempo" da mesma forma que o recurso Flashback Database (10g) possibilita. Neste artigo irei abordar um novo recurso que veio no RMAN do Oracle 12c chamado de Table-Point-In-Time Recovery. Daqui pra frente irei fazer referência a ele apenas como TPITR. Da mesma forma que no TSPITR, iremos notar que o TPITR também se utilizará não só de uma instância auxiliar, como também do utilitário Datapump (expdp/impdp) no processo de restore/recover. Vamos então a prática.
 
[oracle@linux1 ~]$ sqlplus / as sysdba

SQL*Plus: Release 12.1.0.1.0 Production on Sun Jun 1 15:36:29 2014

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

Conectado a:
Oracle Database 12c Enterprise Edition Release 12.1.0.1.0 - 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options

SQL> select * from scott.t1;

        ID
----------
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10

10 linhas selecionadas.

SQL> select sysdate from dual;

SYSDATE
-------------------
01/06/2014 15:36:55

Podemos ver pelo resultado acima, que a tabela T1 de propriedade do usuário SCOTT contém 10 linhas e que a mesma existia às 15:36:55 do dia 01/06/2014. Após realização de um backup do banco de dados com o RMAN, irei dropar a tabela T1 conforme demonstrado abaixo.

SQL> drop table scott.t1 purge;

Tabela eliminada.

SQL> select * from scott.t1;
select * from scott.t1
                    *
ERRO na linha 1:
ORA-00942: a tabela ou view não existe

Pelo fato de eu ter utilizado a opção purge do comando drop table, a mesma não foi para a lixeira (recycle bin). Portanto, não será possível recuperá-la através do flashback drop. Bom, o objetivo então será recuperar a tabela diretamente do backup do banco de dados que fiz previamente através do RMAN. Para me certificar, segue abaixo a prova de que o backup foi realizado.
 
RMAN> list backup;
List of Backup Sets
===================

BS Key  Type LV Size       Device Type Elapsed Time Completion Time
------- ---- -- ---------- ----------- ------------ ---------------
7       Full    404.21M    DISK        00:01:59     01/06/2014
        BP Key: 7   Status: AVAILABLE  Compressed: NO  Tag: TAG20140508T153228
        Piece Name: /u01/app/oracle/fast_recovery_area/BD01/backupset/2014_06_01/o1_mf_nnndf_TAG20140508T153228_9pqmfxl6_.bkp
  List of Datafiles in backup set 7
  File LV Type Ckp SCN    Ckp Time   Name
  ---- -- ---- ---------- ---------- ----
  1       Full 365502     01/06/2014 /u01/app/oracle/oradata/BD01/system01.dbf
  2       Full 365502     01/06/2014 /u01/app/oracle/oradata/BD01/sysaux01.dbf
  3       Full 365502     01/06/2014 /u01/app/oracle/oradata/BD01/undotbs01.dbf
  4       Full 365502     01/06/2014 /u01/app/oracle/oradata/BD01/users01.dbf

BS Key  Type LV Size       Device Type Elapsed Time Completion Time
------- ---- -- ---------- ----------- ------------ ---------------
8       Full    9.61M      DISK        00:00:03     01/06/2014
        BP Key: 8   Status: AVAILABLE  Compressed: NO  Tag: TAG20140508T153228
        Piece Name: /u01/app/oracle/fast_recovery_area/BD01/backupset/2014_06_01/o1_mf_ncnnf_TAG20140508T153228_9pqmkyfx_.bkp
  Control File Included: Ckp SCN: 365548       Ckp time: 01/06/2014

BS Key  Type LV Size       Device Type Elapsed Time Completion Time
------- ---- -- ---------- ----------- ------------ ---------------
9       Full    9.64M      DISK        00:00:02     01/06/2014
        BP Key: 9   Status: AVAILABLE  Compressed: NO  Tag: TAG20140508T153440
        Piece Name: /u01/app/oracle/fast_recovery_area/BD01/autobackup/2014_06_01/o1_mf_s_847035280_9pqml24o_.bkp
  SPFILE Included: Modification time: 01/06/2014
  SPFILE db_unique_name: BD01
  Control File Included: Ckp SCN: 365556       Ckp time: 01/06/2014

Assim como nos métodos DBPITR e TSPITR, para que o processo de recuperação utilizando a técnica TPITR seja possível, será necessário criar um diretório no sistema de arquivos para uso da instância auxiliar que será criada no processo de recover.

[oracle@linux1 ~]$ mkdir /u01/aux_dest

Como eu sei que a tabela existia exatamente às 15:36:35, irei utilizar esse mesmo horário para recuperar a tabela T1. Segue abaixo o comandos necessário para realizar essa operação.

[oracle@linux1 ~]$ rman target /

Recovery Manager: Release 12.1.0.1.0 - Production on Sun Jun 1 15:42:17 2014

Copyright (c) 1982, 2013, Oracle and/or its affiliates.  All rights reserved.

connected to target database: BD01 (DBID=3099510927)

RMAN> recover table SCOTT.T1
2> until time = "to_date('01/06/2014 15:36:55','DD/MM/YYYY HH24:MI:SS')"
3> auxiliary destination '/u01/aux_dest';
Starting recover at 01/06/2014
using target database control file instead of recovery catalog
allocated channel: ORA_DISK_1
channel ORA_DISK_1: SID=272 device type=DISK
RMAN-05026: WARNING: presuming following set of tablespaces applies to specified Point-in-Time

List of tablespaces expected to have UNDO segments
Tablespace SYSTEM
Tablespace UNDOTBS1

Creating automatic instance, with SID='hgkF'

initialization parameters used for automatic instance:
db_name=BD01
db_unique_name=hgkF_pitr_BD01
compatible=12.1.0.0.0
db_block_size=8192
db_files=200
sga_target=1G
processes=80
diagnostic_dest=/u01/app/oracle
db_create_file_dest=/u01/aux_dest
log_archive_dest_1='location=/u01/aux_dest'
#No auxiliary parameter file used


starting up automatic instance BD01

Oracle instance started

Total System Global Area    1068937216 bytes

Fixed Size                     2296576 bytes
Variable Size                281019648 bytes
Database Buffers             780140544 bytes
Redo Buffers                   5480448 bytes
Automatic instance created

contents of Memory Script:
{
# set requested point in time
set until  time "to_date('01/06/2014 15:36:55','DD/MM/YYYY HH24:MI:SS')";
# restore the controlfile
restore clone controlfile;
# mount the controlfile
sql clone 'alter database mount clone database';
# archive current online log
sql 'alter system archive log current';
}
executing Memory Script

executing command: SET until clause

Starting restore at 01/06/2014
allocated channel: ORA_AUX_DISK_1
channel ORA_AUX_DISK_1: SID=83 device type=DISK

channel ORA_AUX_DISK_1: starting datafile backup set restore
channel ORA_AUX_DISK_1: restoring control file
channel ORA_AUX_DISK_1: reading from backup piece /u01/app/oracle/fast_recovery_area/BD01/autobackup/2014_06_01/o1_mf_s_847035280_9pqml24o_.bkp
channel ORA_AUX_DISK_1: piece handle=/u01/app/oracle/fast_recovery_area/BD01/autobackup/2014_06_01/o1_mf_s_847035280_9pqml24o_.bkp tag=TAG20140508T153440
channel ORA_AUX_DISK_1: restored backup piece 1
channel ORA_AUX_DISK_1: restore complete, elapsed time: 00:00:02
output file name=/u01/aux_dest/BD01/controlfile/o1_mf_9pqn27bq_.ctl
Finished restore at 01/06/2014

sql statement: alter database mount clone database

sql statement: alter system archive log current

contents of Memory Script:
{
# set requested point in time
set until  time "to_date('01/06/2014 15:36:55','DD/MM/YYYY HH24:MI:SS')";
# set destinations for recovery set and auxiliary set datafiles
set newname for clone datafile  1 to new;
set newname for clone datafile  3 to new;
set newname for clone datafile  2 to new;
set newname for clone tempfile  1 to new;
# switch all tempfiles
switch clone tempfile all;
# restore the tablespaces in the recovery set and the auxiliary set
restore clone datafile  1, 3, 2;
switch clone datafile all;
}
executing Memory Script

executing command: SET until clause

executing command: SET NEWNAME

executing command: SET NEWNAME

executing command: SET NEWNAME

executing command: SET NEWNAME

renamed tempfile 1 to /u01/aux_dest/BD01/datafile/o1_mf_temp_%u_.tmp in control file

Starting restore at 01/06/2014
using channel ORA_AUX_DISK_1

channel ORA_AUX_DISK_1: starting datafile backup set restore
channel ORA_AUX_DISK_1: specifying datafile(s) to restore from backup set
channel ORA_AUX_DISK_1: restoring datafile 00001 to /u01/aux_dest/BD01/datafile/o1_mf_system_%u_.dbf
channel ORA_AUX_DISK_1: restoring datafile 00003 to /u01/aux_dest/BD01/datafile/o1_mf_undotbs1_%u_.dbf
channel ORA_AUX_DISK_1: restoring datafile 00002 to /u01/aux_dest/BD01/datafile/o1_mf_sysaux_%u_.dbf
channel ORA_AUX_DISK_1: reading from backup piece /u01/app/oracle/fast_recovery_area/BD01/backupset/2014_06_01/o1_mf_nnndf_TAG20140508T153228_9pqmfxl6_.bkp
channel ORA_AUX_DISK_1: piece handle=/u01/app/oracle/fast_recovery_area/BD01/backupset/2014_06_01/o1_mf_nnndf_TAG20140508T153228_9pqmfxl6_.bkp tag=TAG20140508T153228
channel ORA_AUX_DISK_1: restored backup piece 1
channel ORA_AUX_DISK_1: restore complete, elapsed time: 00:02:39
Finished restore at 01/06/2014

datafile 1 switched to datafile copy
input datafile copy RECID=4 STAMP=847035974 file name=/u01/aux_dest/BD01/datafile/o1_mf_system_9pqn2mfs_.dbf
datafile 3 switched to datafile copy
input datafile copy RECID=5 STAMP=847035975 file name=/u01/aux_dest/BD01/datafile/o1_mf_undotbs1_9pqn2mmr_.dbf
datafile 2 switched to datafile copy
input datafile copy RECID=6 STAMP=847035976 file name=/u01/aux_dest/BD01/datafile/o1_mf_sysaux_9pqn2mld_.dbf

contents of Memory Script:
{
# set requested point in time
set until  time "to_date('01/06/2014 15:36:55','DD/MM/YYYY HH24:MI:SS')";
# online the datafiles restored or switched
sql clone "alter database datafile  1 online";
sql clone "alter database datafile  3 online";
sql clone "alter database datafile  2 online";
# recover and open database read only
recover clone database tablespace  "SYSTEM", "UNDOTBS1", "SYSAUX";
sql clone 'alter database open read only';
}
executing Memory Script

executing command: SET until clause

sql statement: alter database datafile  1 online

sql statement: alter database datafile  3 online

sql statement: alter database datafile  2 online

Starting recover at 01/06/2014
using channel ORA_AUX_DISK_1

starting media recovery

archived log for thread 1 with sequence 26 is already on disk as file /u01/app/oracle/fast_recovery_area/BD01/archivelog/2014_06_01/o1_mf_1_26_9pqmqrk0_.arc
archived log file name=/u01/app/oracle/fast_recovery_area/BD01/archivelog/2014_06_01/o1_mf_1_26_9pqmqrk0_.arc thread=1 sequence=26
media recovery complete, elapsed time: 00:00:02
Finished recover at 01/06/2014

sql statement: alter database open read only

contents of Memory Script:
{
   sql clone "create spfile from memory";
   shutdown clone immediate;
   startup clone nomount;
   sql clone "alter system set  control_files =
  ''/u01/aux_dest/BD01/controlfile/o1_mf_9pqn27bq_.ctl'' comment=
 ''RMAN set'' scope=spfile";
   shutdown clone immediate;
   startup clone nomount;
# mount database
sql clone 'alter database mount clone database';
}
executing Memory Script

sql statement: create spfile from memory

database closed
database dismounted
Oracle instance shut down

connected to auxiliary database (not started)
Oracle instance started

Total System Global Area    1068937216 bytes

Fixed Size                     2296576 bytes
Variable Size                285213952 bytes
Database Buffers             775946240 bytes
Redo Buffers                   5480448 bytes

sql statement: alter system set  control_files =   ''/u01/aux_dest/BD01/controlfile/o1_mf_9pqn27bq_.ctl'' comment= ''RMAN set'' scope=spfile

Oracle instance shut down

connected to auxiliary database (not started)
Oracle instance started

Total System Global Area    1068937216 bytes

Fixed Size                     2296576 bytes
Variable Size                285213952 bytes
Database Buffers             775946240 bytes
Redo Buffers                   5480448 bytes

sql statement: alter database mount clone database

contents of Memory Script:
{
# set requested point in time
set until  time "to_date('01/06/2014 15:36:55','DD/MM/YYYY HH24:MI:SS')";
# set destinations for recovery set and auxiliary set datafiles
set newname for datafile  4 to new;
# restore the tablespaces in the recovery set and the auxiliary set
restore clone datafile  4;
switch clone datafile all;
}
executing Memory Script

executing command: SET until clause

executing command: SET NEWNAME

Starting restore at 01/06/2014
allocated channel: ORA_AUX_DISK_1
channel ORA_AUX_DISK_1: SID=11 device type=DISK

channel ORA_AUX_DISK_1: starting datafile backup set restore
channel ORA_AUX_DISK_1: specifying datafile(s) to restore from backup set
channel ORA_AUX_DISK_1: restoring datafile 00004 to /u01/aux_dest/HGKF_PITR_BD01/datafile/o1_mf_users_%u_.dbf
channel ORA_AUX_DISK_1: reading from backup piece /u01/app/oracle/fast_recovery_area/BD01/backupset/2014_06_01/o1_mf_nnndf_TAG20140508T153228_9pqmfxl6_.bkp
channel ORA_AUX_DISK_1: piece handle=/u01/app/oracle/fast_recovery_area/BD01/backupset/2014_06_01/o1_mf_nnndf_TAG20140508T153228_9pqmfxl6_.bkp tag=TAG20140508T153228
channel ORA_AUX_DISK_1: restored backup piece 1
channel ORA_AUX_DISK_1: restore complete, elapsed time: 00:00:03
Finished restore at 01/06/2014

datafile 4 switched to datafile copy
input datafile copy RECID=8 STAMP=847036181 file name=/u01/aux_dest/HGKF_PITR_BD01/datafile/o1_mf_users_9pqng2l9_.dbf

contents of Memory Script:
{
# set requested point in time
set until  time "to_date('01/06/2014 15:36:55','DD/MM/YYYY HH24:MI:SS')";
# online the datafiles restored or switched
sql clone "alter database datafile  4 online";
# recover and open resetlogs
recover clone database tablespace  "USERS", "SYSTEM", "UNDOTBS1", "SYSAUX" delete archivelog;
alter clone database open resetlogs;
}
executing Memory Script

executing command: SET until clause

sql statement: alter database datafile  4 online

Starting recover at 01/06/2014
using channel ORA_AUX_DISK_1

starting media recovery

archived log for thread 1 with sequence 26 is already on disk as file /u01/app/oracle/fast_recovery_area/BD01/archivelog/2014_06_01/o1_mf_1_26_9pqmqrk0_.arc
archived log file name=/u01/app/oracle/fast_recovery_area/BD01/archivelog/2014_06_01/o1_mf_1_26_9pqmqrk0_.arc thread=1 sequence=26
media recovery complete, elapsed time: 00:00:01
Finished recover at 01/06/2014

database opened

contents of Memory Script:
{
# create directory for datapump import
sql "create or replace directory TSPITR_DIROBJ_DPDIR as ''
/u01/aux_dest''";
# create directory for datapump export
sql clone "create or replace directory TSPITR_DIROBJ_DPDIR as ''
/u01/aux_dest''";
}
executing Memory Script

sql statement: create or replace directory TSPITR_DIROBJ_DPDIR as ''/u01/aux_dest''

sql statement: create or replace directory TSPITR_DIROBJ_DPDIR as ''/u01/aux_dest''

Performing export of tables...
   EXPDP> Starting "SYS"."TSPITR_EXP_hgkF_glDz":
   EXPDP> Estimate in progress using BLOCKS method...
   EXPDP> Processing object type TABLE_EXPORT/TABLE/TABLE_DATA
   EXPDP> Total estimation using BLOCKS method: 64 KB
   EXPDP> Processing object type TABLE_EXPORT/TABLE/TABLE
   EXPDP> Processing object type TABLE_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
   EXPDP> Processing object type TABLE_EXPORT/TABLE/STATISTICS/MARKER
   EXPDP> . . exported "SCOTT"."T1"                                5.093 KB      10 rows
   EXPDP> Master table "SYS"."TSPITR_EXP_hgkF_glDz" successfully loaded/unloaded
   EXPDP> ******************************************************************************
   EXPDP> Dump file set for SYS.TSPITR_EXP_hgkF_glDz is:
   EXPDP>   /u01/aux_dest/tspitr_hgkF_20324.dmp
   EXPDP> Job "SYS"."TSPITR_EXP_hgkF_glDz" successfully completed at Sun Jun 1 15:52:23 2014 elapsed 0 00:00:45
Export completed


contents of Memory Script:
{
# shutdown clone before import
shutdown clone abort
}
executing Memory Script

Oracle instance shut down

Performing import of tables...
   IMPDP> Tabela-mestre "SYS"."TSPITR_IMP_hgkF_znug" carregada/descarregada com sucesso
   IMPDP> Iniciando "SYS"."TSPITR_IMP_hgkF_znug":
   IMPDP> Processando o tipo de objeto TABLE_EXPORT/TABLE/TABLE
   IMPDP> Processando o tipo de objeto TABLE_EXPORT/TABLE/TABLE_DATA
   IMPDP> . . importou "SCOTT"."T1"                                5.093 KB      10 linhas
   IMPDP> Processando o tipo de objeto TABLE_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
   IMPDP> Processando o tipo de objeto TABLE_EXPORT/TABLE/STATISTICS/MARKER
   IMPDP> O job "SYS"."TSPITR_IMP_hgkF_znug" foi concluido com sucesso em Dom Jun 1 15:55:09 2014 elapsed 0 00:01:49
Import completed


Removing automatic instance
Automatic instance removed
auxiliary instance file /u01/aux_dest/BD01/datafile/o1_mf_temp_9pqn8x8x_.tmp deleted
auxiliary instance file /u01/aux_dest/HGKF_PITR_BD01/onlinelog/o1_mf_3_9pqngcjb_.log deleted
auxiliary instance file /u01/aux_dest/HGKF_PITR_BD01/onlinelog/o1_mf_2_9pqngbsx_.log deleted
auxiliary instance file /u01/aux_dest/HGKF_PITR_BD01/onlinelog/o1_mf_1_9pqng9r7_.log deleted
auxiliary instance file /u01/aux_dest/HGKF_PITR_BD01/datafile/o1_mf_users_9pqng2l9_.dbf deleted
auxiliary instance file /u01/aux_dest/BD01/datafile/o1_mf_sysaux_9pqn2mld_.dbf deleted
auxiliary instance file /u01/aux_dest/BD01/datafile/o1_mf_undotbs1_9pqn2mmr_.dbf deleted
auxiliary instance file /u01/aux_dest/BD01/datafile/o1_mf_system_9pqn2mfs_.dbf deleted
auxiliary instance file /u01/aux_dest/BD01/controlfile/o1_mf_9pqn27bq_.ctl deleted
auxiliary instance file tspitr_hgkF_20324.dmp deleted
Finished recover at 01/06/2014

Pronto. Após a execução do processo de restore/recover, poderemos ver abaixo que a tabela foi recuperada com sucesso.
 
[oracle@linux1 ~]$ sqlplus / as sysdba

SQL*Plus: Release 12.1.0.1.0 Production on Sun Jun 1 16:24:10 2014

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

Conectado a:
Oracle Database 12c Enterprise Edition Release 12.1.0.1.0 - 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options

SQL> select * from scott.t1;

        ID
----------
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10

10 linhas selecionadas.
  
Bom, da mesma forma que podemos restaurar uma tabela com o nome original, podemos também restaurá-la com um nome diferente. Para isso basta apenas utilizarmos a opção REMAP TABLE. Segue abaixo alguns trechos do processo de recuperação na qual eu irei restaurar a tabela com T1 com o nome de T1_DROP.
 
RMAN> recover table SCOTT.T1
2> until time = "to_date('01/06/2014 15:36:55','DD/MM/YYYY HH24:MI:SS')"
3> auxiliary destination '/u01/aux_dest'
4> remap table SCOTT.T1:T1_DROP;

Performing export of tables...
   EXPDP> Starting "SYS"."TSPITR_EXP_isFB_xdwa":
   EXPDP> Estimate in progress using BLOCKS method...
   EXPDP> Processing object type TABLE_EXPORT/TABLE/TABLE_DATA
   EXPDP> Total estimation using BLOCKS method: 64 KB
   EXPDP> Processing object type TABLE_EXPORT/TABLE/TABLE
   EXPDP> Processing object type TABLE_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
   EXPDP> Processing object type TABLE_EXPORT/TABLE/STATISTICS/MARKER
   EXPDP> . . exported "SCOTT"."T1"                               5.093 KB      10 rows
   EXPDP> Master table "SYS"."TSPITR_EXP_isFB_xdwa" successfully loaded/unloaded
   EXPDP> *****************************************************************************
   EXPDP> Dump file set for SYS.TSPITR_EXP_isFB_xdwa is:
   EXPDP>   /u01/aux_dest/tspitr_isFB_93535.dmp
   EXPDP> Job "SYS"."TSPITR_EXP_isFB_xdwa" successfully completed
Export completed

contents of Memory Script:
{
# shutdown clone before import
shutdown clone abort
}
executing Memory Script

Oracle instance shut down

Performing import of tables...
   IMPDP> Tabela-mestre "SYS"."TSPITR_IMP_isFB_EpCe" carregada/descarregada com sucesso
   IMPDP> Iniciando "SYS"."TSPITR_IMP_isFB_EpCe":
   IMPDP> Processando o tipo de objeto TABLE_EXPORT/TABLE/TABLE
   IMPDP> Processando o tipo de objeto TABLE_EXPORT/TABLE/TABLE_DATA
   IMPDP> . . importou "SCOTT"."T1_DROP"                        5.093 KB      10 linhas
   IMPDP> Processando o tipo de objeto TABLE_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
   IMPDP> Processando o tipo de objeto TABLE_EXPORT/TABLE/STATISTICS/MARKER
   IMPDP> O job "SYS"."TSPITR_IMP_isFB_EpCe" foi concluido com sucesso
Import completed
  
Pronto. Após a finalização do processo de recover podemos ver abaixo a tabela T1_DROP.
 
RMAN> select owner,table_name from dba_tables where owner = 'SCOTT';

using target database control file instead of recovery catalog

OWNER      TABLE_NAME
---------- ---------------
SCOTT      T1
SCOTT      T1_DROP

Para finalizar, existe uma outra opção que podemos utilizar no processo TPITR. Essa opção consiste em recuperar a tabela, mas não importá-la de volta para o banco de dados. Neste caso, apenas um dump contendo a tabela será gerado. Caso queiramos importá-la posteriormente poderemos fazer isso manualmente. Segue abaixo as opções que devemos utilizar para realizar essa operação.
 
RMAN> recover table SCOTT.T1
2> until time = "to_date('01/06/2014 15:36:55','DD/MM/YYYY HH24:MI:SS')"
3> auxiliary destination '/u01/aux_dest'
4> datapump destination '/tmp'
5> dump file 't1.dmp'
6> notableimport;

Performing export of tables...
   EXPDP> Starting "SYS"."TSPITR_EXP_pBbn_otbe":
   EXPDP> Estimate in progress using BLOCKS method...
   EXPDP> Processing object type TABLE_EXPORT/TABLE/TABLE_DATA
   EXPDP> Total estimation using BLOCKS method: 64 KB
   EXPDP> Processing object type TABLE_EXPORT/TABLE/TABLE
   EXPDP> Processing object type TABLE_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
   EXPDP> Processing object type TABLE_EXPORT/TABLE/STATISTICS/MARKER
   EXPDP> . . exported "SCOTT"."T1"                               5.093 KB      10 rows
   EXPDP> Master table "SYS"."TSPITR_EXP_pBbn_otbe" successfully loaded/unloaded
   EXPDP> *****************************************************************************
   EXPDP> Dump file set for SYS.TSPITR_EXP_pBbn_otbe is:
   EXPDP>   /tmp/t1.dmp
   EXPDP> Job "SYS"."TSPITR_EXP_pBbn_otbe" successfully completed
Export completed

Not performing table import after point-in-time recovery

Ao final, poderemos ver que o dump foi gerado no diretório especificado.
 
[oracle@linux1 tmp]$ ls -l /tmp/*.dmp
-rw-r----- 1 oracle oinstall 131072 Mai  8 17:03 /tmp/t1.dmp

segunda-feira, 5 de maio de 2014

Selecionando registros entre intervalos de linhas no Oracle 12c com as cláusulas OFFSET e FETCH

Por Eduardo Legatti

Olá,

No artigo de Abril/2008 eu demonstrei através de um exemplo prático, como selecionar registros de uma tabela dentro de um intervalo específico, fazendo uso da pseudo-coluna ROWNUM. Neste artigo irei demonstrar o mesmo cenário, só que agora, utilizando uma técnica disponível no Oracle 12c que introduziu uma nova cláusula no comando SELECT chamada de row_limiting_clause. Segue abaixo algumas das opções disponíveis nesta nova cláusula:


[ OFFSET offset { ROW | ROWS } ]
[ FETCH { FIRST | NEXT } [ { rowcount | percent PERCENT } ]
    { ROW | ROWS } { ONLY | WITH TIES } ]


Assim como foi feito no artigo de Abril/2008, irei criar uma tabela de teste e demonstrar como selecionar registros dentro de um intervalo específico fazendo uso das opções OFFSET e FETCH disponíveis à partir do Oracle 12c.
 
C:\>sqlplus / as sysdba

SQL*Plus: Release 12.1.0.1.0 Production on Seg Mai 5 10:54:47 2014

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

Conectado a:
Oracle Database 12c Enterprise Edition Release 12.1.0.1.0 - 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options

SQL> create table teste as select level id,
  2  substr(dbms_random.string('U',10),1,10) valor
  3  from dual connect by level <= 10;

Tabela criada.

SQL> select * from teste order by valor;

        ID VALOR
---------- ----------
         2 ARNKSCLTGX
         8 BIQWGDVRUD
         1 BPNHTRDKWL
        10 JNHCSENXWG
         7 MYVTHQHOSY
         3 PECVQGHWAU
         4 VLXVQQBIGY
         9 WHRKAADTQT
         5 XWQINROZMP
         6 ZVKFERWVDT

10 linhas selecionadas. 

Bom, com os registros demonstrados acima, o que deverá ser feito para que possamos obter a quarta (4ª) e a quinta (5ª) linha da tabela (ID 10 e 7)?  

SQL> SELECT id,valor,rownum
  2    FROM (SELECT id,valor
  3            FROM (SELECT id,valor
  4                  FROM teste
  5                  ORDER by valor));

        ID VALOR          ROWNUM
---------- ---------- ----------
         2 ARNKSCLTGX          1
         8 BIQWGDVRUD          2
         1 BPNHTRDKWL          3
        10 JNHCSENXWG          4
         7 MYVTHQHOSY          5
         3 PECVQGHWAU          6
         4 VLXVQQBIGY          7
         9 WHRKAADTQT          8
         5 XWQINROZMP          9
         6 ZVKFERWVDT         10

10 linhas selecionadas.
  
De acordo com o resultado acima, sabemos que as linhas de ID 10 e 7 são as linhas que queremos obter. A seguir, irei aplicar a técnica demonstrada no artigo de Abril/2008 através da pseudo-coluna ROWNUM e, mais a frente, demonstrar a nova cláusula row_limiting_clause disponível no Oracle 12c.
 
-- Utilizando a técnica com o ROWNUM
SQL> SELECT id,valor
  2        FROM (SELECT id,valor, rownum rn
  3                FROM (SELECT *
  4                       FROM (select id,valor from teste)
  5                       ORDER BY valor)
  6               WHERE rownum <= 5)
  7        WHERE rn >= 4;

        ID VALOR
---------- ----------
        10 JNHCSENXWG
         7 MYVTHQHOSY


-- Utilizando a cláusula row_limiting_clause do Oracle 12c
SQL> SELECT id,valor
  2  FROM   teste
  3  ORDER BY valor
  4  OFFSET 3 ROWS FETCH NEXT 2 ROWS ONLY;

        ID VALOR
---------- ----------
        10 JNHCSENXWG
         7 MYVTHQHOSY

No mais, podemos perceber que com o Oracle 12c esta tarefa ficou muito mais simples e intuitiva. Na instrução SQL acima, o valor 3 significa o número da linha que deverá ser o ponto de partida do intervalo, e o valor 2 a quantidade de linhas que deverão ser retornadas à partir  do ponto de partida. Vale a pena observar que a linha de ponto de partida (OFFSET) não é incluída no resultado.

quarta-feira, 2 de abril de 2014

Oracle Multitenant: Abordando a realização de backups com o RMAN nos Pluggable Databases (PDB) e Container Databases (CDB) no Oracle 12c

Por Eduardo Legatti

Olá,




Nos artigos de Fevereiro/2014 e Março/2014 abordei sobre a arquitetura Multitenant do Oracle 12c de forma prática afim de demonstrar alguns conceitos e propriedades por trás dos bancos de dados de containers (CDBs) e dos bancos de dados plugáveis (PDBs). Neste artigo irei abordar a realização de backups dos bancos de dados CDBs e PDBs através do utilitário RMAN (Recovery Manager). Vale a pena salientar que irei focar apenas na realização dos backups, sem qualquer ação de recovery. A seguir, irei conectar no banco de dados de container CDB01 e realizar o backup do mesmo utilizando o RMAN. Pode-se notar abaixo que no RMAN da versão 12c é possível executar instruções SQL da mesma forma que no SQL*Plus.


C:\>set ORACLE_SID=CDB01

C:\>rman target /

Gerenciador de Recuperação: Release 12.1.0.1.0 - Production on Qua Abr 2 11:34:47 2014

Copyright (c) 1982, 2013, Oracle and/or its affiliates.  All rights reserved.

conectado ao banco de dados de destino: CDB01 (DBID=1370556575)

RMAN> select con_id,dbid,name,open_mode from v$pdbs;

    CON_ID       DBID NAME              OPEN_MODE
---------- ---------- ----------------- ----------
         2 4076210644 PDB$SEED          READ ONLY
         3 3898013363 PDB01             READ WRITE
         4 3947824578 PDB02             READ WRITE
         5 4001514065 PDB03             READ WRITE

No resultado do SQL acima, pode-se notar a existência de 4 bancos de dados plugáveis (PDBs). Por padrão, o banco de dados PDB$SEED usado como template para criação de novos bancos de dados PDBs se mantém no estado somente leitura (READ ONLY). Abaixo irei realizar o backup do banco de dados CDB01. Como pré requisito para realização de Hot Backup, o banco de dados CDB01 foi alterado para operar no modo ARCHIVELOG.


Backup do Container Database (CDB) 

RMAN> backup database plus archivelog;

Iniciando backup em 02/04/14
log atual arquivado
usar o arquivo de controle do banco de dados de destino em vez do catálogo de recuperação
canal alocado: ORA_DISK_1
canal ORA_DISK_1: SID=23 tipo de dispositivo=DISK
canal ORA_DISK_1: iniciando conjunto de backups de log arquivado
canal ORA_DISK_1: especificando log(s) arquivado no conjunto de backups
thread do log arquivado de entrada=1 sequência=11 RECID=1 STAMP=842882988
canal ORA_DISK_1: iniciando o componente 1 em 02/04/14
canal ORA_DISK_1: componente 1 finalizado em 02/04/14
handle de componente=D:\ORACLE\APP\FAST_RECOVERY_AREA\CDB01\BACKUPSET\2014_04_02\O1_MF...
canal ORA_DISK_1: conjunto de backups concluído, tempo decorrido: 00:00:01
Finalizado backup em 02/04/14

Iniciando backup em 02/04/14
utilizando o canal ORA_DISK_1
canal ORA_DISK_1: iniciando conjunto de backup completo de arquivo de dados
canal ORA_DISK_1: especificando arquivo(s) de dados no conjunto de backups
número do arquivo=00001 nome=D:\ORACLE\APP\ORADATA\CDB01\SYSTEM01.DBF
número do arquivo=00005 nome=D:\ORACLE\APP\ORADATA\CDB01\UNDOTBS01.DBF
número do arquivo=00003 nome=D:\ORACLE\APP\ORADATA\CDB01\SYSAUX01.DBF
número do arquivo=00006 nome=D:\ORACLE\APP\ORADATA\CDB01\USERS01.DBF
canal ORA_DISK_1: iniciando o componente 1 em 02/04/14
canal ORA_DISK_1: componente 1 finalizado em 02/04/14
handle de componente=D:\ORACLE\APP\FAST_RECOVERY_AREA\CDB01\BACKUPSET\2014_04_02\O1_MF...
canal ORA_DISK_1: conjunto de backups concluído, tempo decorrido: 00:02:26
canal ORA_DISK_1: iniciando conjunto de backup completo de arquivo de dados
canal ORA_DISK_1: especificando arquivo(s) de dados no conjunto de backups
número do arquivo=00004 nome=D:\ORACLE\APP\ORADATA\CDB01\PDBSEED\SYSAUX01.DBF
número do arquivo=00002 nome=D:\ORACLE\APP\ORADATA\CDB01\PDBSEED\SYSTEM01.DBF
canal ORA_DISK_1: iniciando o componente 1 em 02/04/14
canal ORA_DISK_1: componente 1 finalizado em 02/04/14
handle de componente=D:\ORACLE\APP\FAST_RECOVERY_AREA\CDB01\02C6D349454A4F42BE1E114F23...
canal ORA_DISK_1: conjunto de backups concluído, tempo decorrido: 00:01:05
canal ORA_DISK_1: iniciando conjunto de backup completo de arquivo de dados
canal ORA_DISK_1: especificando arquivo(s) de dados no conjunto de backups
número do arquivo=00013 nome=D:\ORACLE\APP\ORADATA\CDB01\PDB01\SYSAUX01.DBF
número do arquivo=00012 nome=D:\ORACLE\APP\ORADATA\CDB01\PDB01\SYSTEM01.DBF
número do arquivo=00014 nome=D:\ORACLE\APP\ORADATA\CDB01\PDB01\PDB01_USERS01.DBF
canal ORA_DISK_1: iniciando o componente 1 em 02/04/14
canal ORA_DISK_1: componente 1 finalizado em 02/04/14
handle de componente=D:\ORACLE\APP\FAST_RECOVERY_AREA\CDB01\A1D71A8D231B4153A6189ECF7C...
canal ORA_DISK_1: conjunto de backups concluído, tempo decorrido: 00:01:15
canal ORA_DISK_1: iniciando conjunto de backup completo de arquivo de dados
canal ORA_DISK_1: especificando arquivo(s) de dados no conjunto de backups
número do arquivo=00018 nome=D:\ORACLE\APP\ORADATA\CDB01\PDB02\SYSAUX01.DBF
número do arquivo=00017 nome=D:\ORACLE\APP\ORADATA\CDB01\PDB02\SYSTEM01.DBF
canal ORA_DISK_1: iniciando o componente 1 em 02/04/14
canal ORA_DISK_1: componente 1 finalizado em 02/04/14
handle de componente=D:\ORACLE\APP\FAST_RECOVERY_AREA\CDB01\BBF9D856E6144A5586175255D5...
canal ORA_DISK_1: conjunto de backups concluído, tempo decorrido: 00:01:05
canal ORA_DISK_1: iniciando conjunto de backup completo de arquivo de dados
canal ORA_DISK_1: especificando arquivo(s) de dados no conjunto de backups
número do arquivo=00023 nome=D:\ORACLE\APP\ORADATA\CDB01\PDB03\SYSAUX01.DBF
número do arquivo=00022 nome=D:\ORACLE\APP\ORADATA\CDB01\PDB03\SYSTEM01.DBF
número do arquivo=00024 nome=D:\ORACLE\APP\ORADATA\CDB01\PDB03\PDB01_USERS01.DBF
canal ORA_DISK_1: iniciando o componente 1 em 02/04/14
canal ORA_DISK_1: componente 1 finalizado em 02/04/14
handle de componente=D:\ORACLE\APP\FAST_RECOVERY_AREA\CDB01\8C150C75FFDE4362A4CDF6C7B2...
canal ORA_DISK_1: conjunto de backups concluído, tempo decorrido: 00:00:55
Finalizado backup em 02/04/14

Iniciando backup em 02/04/14
log atual arquivado
utilizando o canal ORA_DISK_1
canal ORA_DISK_1: iniciando conjunto de backups de log arquivado
canal ORA_DISK_1: especificando log(s) arquivado no conjunto de backups
thread do log arquivado de entrada=1 sequência=12 RECID=2 STAMP=842883401
canal ORA_DISK_1: iniciando o componente 1 em 02/04/14
canal ORA_DISK_1: componente 1 finalizado em 02/04/14
handle de componente=D:\ORACLE\APP\FAST_RECOVERY_AREA\CDB01\BACKUPSET\2014_04_02\O1_MF...
canal ORA_DISK_1: conjunto de backups concluído, tempo decorrido: 00:00:01
Finalizado backup em 02/04/14

Iniciando Control File and SPFILE Autobackup em 02/04/14
handle de componente=D:\ORACLE\APP\FAST_RECOVERY_AREA\CDB01\AUTOBACKUP\2014_04_02\O1_M...
Finalizado Control File and SPFILE Autobackup em 02/04/14

No resultado apresentado acima, pode-se notar que ao realizar o backup de um banco de dados de container CDB, o mesmo acontece com todos os bancos de dados PDBs existentes.


Backup do Container ROOT (CDB$ROOT)

O backup do banco de dados de container ROOT é semelhante ao backup do banco de dados de CDB, com a diferença de que os bancos de dados PDB não são incluídos no backup. Segue abaixo a demonstração de realização do backup do container ROOT.

RMAN> backup database root plus archivelog;

Iniciando backup em 02/04/14
log atual arquivado
usar o arquivo de controle do banco de dados de destino em vez do catálogo de recuperação
canal alocado: ORA_DISK_1
canal ORA_DISK_1: SID=34 tipo de dispositivo=DISK
canal ORA_DISK_1: iniciando conjunto de backups de log arquivado
canal ORA_DISK_1: especificando log(s) arquivado no conjunto de backups
thread do log arquivado de entrada=1 sequência=13 RECID=3 STAMP=842884398
canal ORA_DISK_1: iniciando o componente 1 em 02/04/14
canal ORA_DISK_1: componente 1 finalizado em 02/04/14
handle de componente=D:\ORACLE\APP\FAST_RECOVERY_AREA\CDB01\BACKUPSET\2014_04_02\O1_MF...
canal ORA_DISK_1: conjunto de backups concluído, tempo decorrido: 00:00:01
Finalizado backup em 02/04/14

Iniciando backup em 02/04/14
utilizando o canal ORA_DISK_1
canal ORA_DISK_1: iniciando conjunto de backup completo de arquivo de dados
canal ORA_DISK_1: especificando arquivo(s) de dados no conjunto de backups
número do arquivo=00001 nome=D:\ORACLE\APP\ORADATA\CDB01\SYSTEM01.DBF
número do arquivo=00005 nome=D:\ORACLE\APP\ORADATA\CDB01\UNDOTBS01.DBF
número do arquivo=00003 nome=D:\ORACLE\APP\ORADATA\CDB01\SYSAUX01.DBF
número do arquivo=00006 nome=D:\ORACLE\APP\ORADATA\CDB01\USERS01.DBF
canal ORA_DISK_1: iniciando o componente 1 em 02/04/14
canal ORA_DISK_1: componente 1 finalizado em 02/04/14
handle de componente=D:\ORACLE\APP\FAST_RECOVERY_AREA\CDB01\BACKUPSET\2014_04_02\O1_MF...
canal ORA_DISK_1: conjunto de backups concluído, tempo decorrido: 00:02:15
Finalizado backup em 02/04/14

Iniciando backup em 02/04/14
log atual arquivado
utilizando o canal ORA_DISK_1
canal ORA_DISK_1: iniciando conjunto de backups de log arquivado
canal ORA_DISK_1: especificando log(s) arquivado no conjunto de backups
thread do log arquivado de entrada=1 sequência=14 RECID=4 STAMP=842884538
canal ORA_DISK_1: iniciando o componente 1 em 02/04/14
canal ORA_DISK_1: componente 1 finalizado em 02/04/14
handle de componente=D:\ORACLE\APP\FAST_RECOVERY_AREA\CDB01\BACKUPSET\2014_04_02\O1_MF...
canal ORA_DISK_1: conjunto de backups concluído, tempo decorrido: 00:00:01
Finalizado backup em 02/04/14

Iniciando Control File and SPFILE Autobackup em 02/04/14
handle de componente=D:\ORACLE\APP\FAST_RECOVERY_AREA\CDB01\AUTOBACKUP\2014_04_02\O1_M...
Finalizado Control File and SPFILE Autobackup em 02/04/14 

Backup dos Pluggable Databases (PDB)



É possível realizar o backup de um ou mais bancos de dados plugáveis de uma só uma vez. Segue abaixo o exemplo de realização de backup dos bancos de dados PDB01 e PDB02.

RMAN> backup pluggable database pdb01, pdb02 plus archivelog;

Iniciando backup em 02/04/14
log atual arquivado
usar o arquivo de controle do banco de dados de destino em vez do catálogo de recuperação
canal alocado: ORA_DISK_1
canal ORA_DISK_1: SID=30 tipo de dispositivo=DISK
canal ORA_DISK_1: iniciando conjunto de backups de log arquivado
canal ORA_DISK_1: especificando log(s) arquivado no conjunto de backups
thread do log arquivado de entrada=1 sequência=13 RECID=3 STAMP=842884398
thread do log arquivado de entrada=1 sequência=14 RECID=4 STAMP=842884538
thread do log arquivado de entrada=1 sequência=15 RECID=5 STAMP=842885189
canal ORA_DISK_1: iniciando o componente 1 em 02/04/14
canal ORA_DISK_1: componente 1 finalizado em 02/04/14
handle de componente=D:\ORACLE\APP\FAST_RECOVERY_AREA\CDB01\BACKUPSET\2014_04_02\O1_MF...
canal ORA_DISK_1: conjunto de backups concluído, tempo decorrido: 00:00:01
Finalizado backup em 02/04/14

Iniciando backup em 02/04/14
utilizando o canal ORA_DISK_1
canal ORA_DISK_1: iniciando conjunto de backup completo de arquivo de dados
canal ORA_DISK_1: especificando arquivo(s) de dados no conjunto de backups
número do arquivo=00013 nome=D:\ORACLE\APP\ORADATA\CDB01\PDB01\SYSAUX01.DBF
número do arquivo=00012 nome=D:\ORACLE\APP\ORADATA\CDB01\PDB01\SYSTEM01.DBF
número do arquivo=00014 nome=D:\ORACLE\APP\ORADATA\CDB01\PDB01\PDB01_USERS01.DBF
canal ORA_DISK_1: iniciando o componente 1 em 02/04/14
canal ORA_DISK_1: componente 1 finalizado em 02/04/14
handle de componente=D:\ORACLE\APP\FAST_RECOVERY_AREA\CDB01\02C6D349454A4F42BE1E114F23...
canal ORA_DISK_1: conjunto de backups concluído, tempo decorrido: 00:01:05
canal ORA_DISK_1: iniciando conjunto de backup completo de arquivo de dados
canal ORA_DISK_1: especificando arquivo(s) de dados no conjunto de backups
número do arquivo=00018 nome=D:\ORACLE\APP\ORADATA\CDB01\PDB02\SYSAUX01.DBF
número do arquivo=00017 nome=D:\ORACLE\APP\ORADATA\CDB01\PDB02\SYSTEM01.DBF
canal ORA_DISK_1: iniciando o componente 1 em 02/04/14
canal ORA_DISK_1: componente 1 finalizado em 02/04/14
handle de componente=D:\ORACLE\APP\FAST_RECOVERY_AREA\CDB01\BBF9D856E6144A5586175255D5...
canal ORA_DISK_1: conjunto de backups concluído, tempo decorrido: 00:01:15
Finalizado backup em 02/04/14

Iniciando backup em 02/04/14
log atual arquivado
utilizando o canal ORA_DISK_1
canal ORA_DISK_1: iniciando conjunto de backups de log arquivado
canal ORA_DISK_1: especificando log(s) arquivado no conjunto de backups
thread do log arquivado de entrada=1 sequência=16 RECID=6 STAMP=842885334
canal ORA_DISK_1: iniciando o componente 1 em 02/04/14
canal ORA_DISK_1: componente 1 finalizado em 02/04/14
handle de componente=D:\ORACLE\APP\FAST_RECOVERY_AREA\CDB01\BACKUPSET\2014_04_02\O1_MF...
canal ORA_DISK_1: conjunto de backups concluído, tempo decorrido: 00:00:01
Finalizado backup em 02/04/14

Iniciando Control File and SPFILE Autobackup em 02/04/14
handle de componente=D:\ORACLE\APP\FAST_RECOVERY_AREA\CDB01\AUTOBACKUP\2014_04_02\O1_M...
Finalizado Control File and SPFILE Autobackup em 02/04/14

Até agora demonstrei a realização de backups dos bancos de dados estando conectado no banco de dados de container ROOT. É possível realizar o backup de um banco de dados PDB conectando diretamente no mesmo pelo RMAN através de um serviço TNS. Como exemplo, segue abaixo o serviço TNS criado no TNSNAMES.ORA da minha máquina local.

PDB01 =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = PDB01)
    )
  )


A seguir, irei utilizar o serviço PDB01 acima para conectar no banco de dados PDB01. Após a realização da conexão será possível realizar o backup do mesmo como demonstrado abaixo.
 
C:\>rman target /@PDB01

Gerenciador de Recuperação: Release 12.1.0.1.0 - Production on Qua Abr 2 11:58:00 2014

Copyright (c) 1982, 2013, Oracle and/or its affiliates.  All rights reserved.

conectado ao banco de dados de destino: CDB01 (DBID=1370556575)

RMAN> backup database;

Iniciando backup em 02/04/14
usar o arquivo de controle do banco de dados de destino em vez do catálogo de recuperação
canal alocado: ORA_DISK_1
canal ORA_DISK_1: SID=35 tipo de dispositivo=DISK
canal ORA_DISK_1: iniciando conjunto de backup completo de arquivo de dados
canal ORA_DISK_1: especificando arquivo(s) de dados no conjunto de backups
número do arquivo=00013 nome=D:\ORACLE\APP\ORADATA\CDB01\PDB01\SYSAUX01.DBF
número do arquivo=00012 nome=D:\ORACLE\APP\ORADATA\CDB01\PDB01\SYSTEM01.DBF
número do arquivo=00014 nome=D:\ORACLE\APP\ORADATA\CDB01\PDB01\PDB01_USERS01.DBF
canal ORA_DISK_1: iniciando o componente 1 em 02/04/14
canal ORA_DISK_1: componente 1 finalizado em 02/04/14
handle de componente=D:\ORACLE\APP\FAST_RECOVERY_AREA\CDB01\02C6D349454A4F42BE1E114F23...
canal ORA_DISK_1: conjunto de backups concluído, tempo decorrido: 00:01:15
Finalizado backup em 02/04/14

Iniciando Control File and SPFILE Autobackup em 02/04/14
handle de componente=D:\ORACLE\APP\FAST_RECOVERY_AREA\CDB01\AUTOBACKUP\2014_04_02\O1_M...
Finalizado Control File and SPFILE Autobackup em 02/04/14

quarta-feira, 5 de março de 2014

Oracle Multitenant: Clonando e movendo Pluggable Databases (PDB) entre Container Databases (CDB) no Oracle 12c

Por Eduardo Legatti

Olá,

No artigo de Fevereiro/2014 fiz uma breve introdução sobre a arquitetura Multitenant do Oracle 12c abordando a criação dos bancos de dados de forma prática e apresentando alguns conceitos por trás dos bancos de dados de containers (CDBs) e dos bancos de dados plugáveis (PDBs). Neste artigo irei abordar o conceito de plugar (plug) e desplugar (unplug) os banco de dados PDBs. Irei demonstrar as etapas para mover um banco de dados PDB para um outro banco de dados CDB e também demonstrar o processo de clonagem de um banco de dados PDB dentro de um mesmo banco de dados CDB. Irei realizar a demonstração utilizando tanto o DBCA quanto o processo manual através do SQL*Plus. A figura abaixo ilustra muito bem o que eu irei abordar a seguir.


 

Movendo um PDB para outro container root CDB com o DBCA

Abaixo irei demonstrar o processo de desplugar o banco de dados plugável PDB02 do banco de dados CDB01 com o intuito de plugá-lo mais a frente no banco de dados CDB02 que foi criado previamente. Segue abaixo as etapas para realizar o processo de "unplug" através do DBCA.









Após o processo de desplugar o banco de dados PDB02 do banco de dados de container CDB01, veremos abaixo os arquivos que foram gerados. No meu exemplo eu usei como destino o diretório C:\TEMP.

C:\>dir TEMP
 O volume na unidade C não tem nome.
 O Número de Série do Volume é 26BD-71DB

 Pasta de C:\TEMP

05/03/2014  08:42       199.667.673 CDB01_PDB02.tar.gz
05/03/2014  08:41             3.688 CDB01_PDB02.xml
               2 arquivo(s)    199.671.361 bytes
               2 pasta(s)   10.368.245.760 bytes disponíveis


A seguir irei realizar o processo de plugar o banco de dados PDB02 contido nos arquivos acima no banco de dados container CDB02 através do DBCA. Seguindo os mesmos procedimentos demonstrados no processo de "unplug", na tela de gerenciar banco de dados plugáveis, irei escolher a opção de criar um banco de dados plugável e escolher a instância CDB02 conforme demonstrado abaixo.









Após a criação do banco de dados PDB02 no container CDB02, poderemos ver que o mesmo já se encontra aberto e no estado READ WRITE conforme demonstrado abaixo.

C:\>set ORACLE_SID=CDB02

C:\>sqlplus / as sysdba

SQL*Plus: Release 12.1.0.1.0 Production on Qua Mar 5 09:15:28 2014

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

Conectado a:
Oracle Database 12c Enterprise Edition Release 12.1.0.1.0 - 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options

SQL> select pdb_name, status from cdb_pdbs;

PDB_NAME              STATUS
--------------------- -------------
PDB$SEED              NORMAL
PDB02                 NORMAL

SQL> select name, open_mode from v$pdbs;

NAME                    OPEN_MODE
----------------------- ----------
PDB$SEED                READ ONLY
PDB02                   READ WRITE  

Identifiquei que os arquivos relacionados ao banco de dados PDB02 do container CDB01 não foram apagados fisicamente após o processo de "unplug". No mais, o banco de dados PDB02 que foi desplugado do container root CDB01 poderá ser criado (plugado) novamente no container root CDB01 do mesmo modo que foi realizado no container root CDB02.


Movendo um PDB para outro container root CDB com o SQL*Plus

Do mesmo modo que realizei o processo de unplug/plug através da interface gráfica com o DBCA, irei realizar o mesmo processo, só que agora de forma manual utilizando o SQL*Plus. Vale a pena salientar que quando um PDB está plugado em um CDB, este CDB mantém informações de seus metadados como o nome do PDB enquanto ele está plugado ao CDB e os nomes e caminhos dos data files. Algumas informações estão presentes nas tabelas de dicionário de dados e nos control files do container root CDB. Como foi demonstrado acima, o processo de "unplug" estes metadados são gravados em um arquivo XML acompanhados dos seus data files. O processo manual é um pouco diferente já que não teremos um arquivo .TAR.GZ contendo os data files do PDB. Segue abaixo o processo manual de "unplug" através de comandos SQL.

C:\>set ORACLE_SID=CDB01

C:\>sqlplus / as sysdba

SQL> alter pluggable database PDB02 close immediate;

Banco de dados plugável alterado.

SQL> alter pluggable database PDB02 unplug into 'C:\TEMP\PDB02.XML';

Banco de dados plugável alterado. 

O processo de desplugar o banco de dados PDB através de comandos SQL é bastante simples. Como demonstrado acima, foi necessário apenas realizar o SHUTDOWN do banco de dados PDB e executar o comando ALTER PLUGGABLE DATABASE ... UNPLUG definindo o destino do arquivo XML contendo os metadados do banco de dados. Agora irei plugar banco de dados PDB02 no banco de dados container CDB02 manualmente como demonstrado a seguir.

C:\>set ORACLE_SID=CDB02

C:\>sqlplus / as sysdba

SQL> create pluggable database PDB02
  2  using 'C:\TEMP\PDB02.XML'
  3  copy file_name_convert =
  4  (
  5   'D:\oracle\app\oradata\CDB01\PDB02',
  6   'D:\oracle\app\oradata\CDB02\PDB02'
  7  );

Banco de dados plugável criado.

SQL> alter pluggable database PDB02 open;

Banco de dados plugável alterado. 

Como demonstrado acima, o processo de plugar o banco de dados PDB nada mais é do que criar um banco de dados PDB utilizando como fonte de informação o arquivo de metadados XML gerado no processo de unplug. O processo também consiste em copiar os data files através da cláusula COPY do comando CREATE PLUGGABLE DATABASE.


Plugando o PDB de volta ao container root CDB de origem

Se eu tentar plugar novamente o banco de dados PDBD02 no container root CDB01, o erro ORA-65012 será emitido informando que o banco de dados plugável PDB02 já existe. Ele existe, mas foi desplugado. Em um primeiro momento isso pode ser bem confuso. Portanto, irei dropar o banco de dados PDB02 sem remover os seus data files.

C:\>set ORACLE_SID=CDB01

C:\>sqlplus / as sysdba

SQL> select pdb_name, status from cdb_pdbs;

PDB_NAME                                STATUS
--------------------------------------- -------------
PDB$SEED                                NORMAL
PDB01                                   NORMAL
PDB02                                   UNPLUGGED

SQL> drop pluggable database PDB02 keep datafiles;

Banco de dados plugável eliminado.  

Com o banco de dados PDB02 dropado, irei criá-lo novamente reaproveitando os datas files existentes.

SQL> create pluggable database PDB02
  2  using 'C:\TEMP\PDB02.XML' nocopy tempfile reuse;

Banco de dados plugável criado.

SQL> alter pluggable database PDB02 open;

Banco de dados plugável alterado.   

Clonando um PDB em um mesmo container root CDB

A arquitetura Multitenant do Oracle 12c nos permite criar o clone de um PDB em um mesmo CDB. Já que o DBCA não nos fornece esse tipo de opção, nos resta apenas o processo manual através de comandos SQL. Fazendo uso do SQL*Plus, conectarei no banco de dados de container CDB01, e demonstrarei um exemplo de clonagem de PDBs. Irei criar abaixo o banco de dados PDB03 que será um clone do banco de dados PDB01.

C:\>set ORACLE_SID=CDB01

C:\>sqlplus / as sysdba

SQL> alter pluggable database PDB01 close immediate;

Banco de dados plugável alterado.

SQL> alter pluggable database PDB01 open read only;

Banco de dados plugável alterado.

SQL> create pluggable database PDB03 from PDB01
  2  file_name_convert =
  3  (
  4   'D:\oracle\app\oradata\CDB01\PDB01',
  5   'D:\oracle\app\oradata\CDB01\PDB03'
  6  );

Banco de dados plugável criado. 

Pronto. A clonagem do banco de dados PDB01 foi realizada utilizando o comando CREATE PLUGGABLE DATABASE ... FROM ... conforme demonstrado acima. Vale a pena salientar que o banco de dados de origem PDB01 foi fechado e seu status alterado para READ ONLY da mesma forma que o banco de dados de template PDB$SEED. Após o processo de clonagem, poderemos ver abaixo que o banco de dados PDB03 permaneceu no estado MOUNT. Já que ambos os bancos de dados PDB01 e PDB03 não se encontram no estado READ/WRITE, poderemos alterar os status dos mesmos com um único comando conforme demonstrado a seguir.

SQL> select name, open_mode from v$pdbs;

NAME                                   OPEN_MODE
-------------------------------------- ----------
PDB$SEED                               READ ONLY
PDB01                                  READ ONLY
PDB02                                  READ WRITE
PDB03                                  MOUNTED

SQL> alter pluggable database PDB01,PDB03 open read write force;

Banco de dados plugável alterado. 

Dependendo do ambiente de banco de dados em questão, o processo de clonagem talvez não seja o mais adequado para um ambiente de produção já que o banco de dados PDB de origem precisará ficar indisponível para acesso de escrita por um determinado período até a finalização do processo de clonagem. Acredito que o processo de clonagem seja bastante útil em ambiente de desenvolvimento. No mais, sempre teremos a opção de utilizar outras técnicas de clonagem como, por exemplo, o RMAN DUPLICATE.

Postagens populares