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


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 Janeiro/2014 e Fevereiro/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.

segunda-feira, 3 de fevereiro de 2014

Oracle Multitenant: Abordando a arquitetura e criação do Container Database (CDB) e Pluggable Databases no Oracle 12c

Por Eduardo Legatti

Olá, 



Como já abordado no artigo de Junho/2013, o Oracle Database 12c agora suporta uma nova arquitetura (option) chamada Multitenant que permite que tenhamos um ou mais "sub-bancos de dados" dentro e um único "super banco de dados". Este "super banco de dados" é chamado de CDB (Container Database) e os "sub-bancos de dados" são chamados de PDBs (Pluggable Databases) ou containers de bancos de dados plugáveis. O CDB também pode ser chamado de container ROOT (CDB$ROOT). Em outras palavras, essa nova arquitetura permite a criação de muitos PDBs dentro de um único CDB. A idéia principal por trás deste conceito consiste em permitir um uso mais eficiente dos recursos do sistema, além de oferecer um gerenciamento mais simplificado.

Até o Oracle 12c release 12.1, o número máximo de PDBs que podem ser criados é de 252. O Oracle 12c suporta tanto a criação de bancos de dados CDBs quanto a criação de bancos de dados não-CDBs que são aqueles que temos o costume de usar e que possuem a arquitetura que conhecemos nas versões 11g, 10g, 9i, 8i, etc. Aliás, é possível atualizarmos um banco de dados Oracle pré 12c (não-CDB) para o Oracle 12c e continuarmos a operá-lo como tal. Do ponto de vista de um cliente que se conecta via Oracle Net a uma instância do Oracle, o PDB é o banco de dados. Do ponto de vista do sistema operacional, o CDB é que é o banco de dados. No mais, neste artigo irei demonstrar a criação de um banco de dados CDB usando o DBCA (Database Configuration Assistant) e a criação de dois bancos PDBs (um via DBCA e outro manualmente via SQL*Plus). A minha intenção é demonstrar algumas propriedades e características dessa nova arquitetura de forma simples e objetiva.

Vale a pena salientar que essa arquitetura permite que tenhamos vários PDBs no mesmo CDB cada um tendo usuários, tablespaces, database links, directories, etc... com o mesmo nome. Por exemplo, poderemos ter o usuário SCOTT tanto no banco de dados PDB01 quanto no banco PDB02. Do ponto de vista da arquitetura, veremos mais abaixo que um CDB é composto de um container root chamado de CDB$ROOT responsável por armazenar o dicionário de dados, o motor PL/SQL e usuários comuns (common users). Outro componente é um seed de um banco de dados PDB chamado PDB$SEED que é utilizado como template para criação de novos PDBs.

Segue abaixo algumas características e peculiaridades da arquitetura física e lógica do Oracle 12c Multitenant:

  • Multitenant é uma option do Oracle Enterprise Edition.
  • Um container é definido como uma coleção de data files e metadados que existem dentro de um CDB. Pode ser root, seed ou PDB.
  • Um container CDB é definido como um banco de dados capaz de abrigar um ou mais banco de dados plugáveis (PDBs).
  • Um PDB (banco de dados plugável) é um tipo especial de container que pode ser facilmente clonado. Se necessário, um PDB também pode ser transferido de um CDB para outro.
  • Um container CDB pode conter zero, um ou mais PDBs (Até o release 12.1 máximo de 252).
  • As tablespaces SYSTEM e SYSAUX existem tanto no container root CDB quanto nos PDBs.
  • Existe apenas uma tablespace de UNDO para todo o CDB, ou seja, a tablespace de UNDO é compartilhada.
  • Existe apenas um conjunto de control files e online redo log files para todo o CDB, ou seja, os mesmos são compartilhados.
  • Pode ser criada uma tablespace TEMP default para todo o CDB, mas cada PDB pode ter tablespaces temporárias adicionais.
  • Os arquivos relacionados ao Oracle Net como listener.ora, tnsnames.ora, e sqlnet.ora para todo o CDB. Todos os PDBs utilizam esses mesmos arquivos.
  • Existe apenas um conjunto de processos de segundo plano (background processes) que são compartilhados pelo CDB e todos os PDBs.
  • Existe apenas uma única SGA (System Global Area) compartilhada para todos os PDBs.
  • Quando o CDB sofre shutdown todos os PDBs também sofrerão automaticamente shutdown.
  • Quando o CDB é aberto (startup) os PDBs permanecem no estado MOUNT e precisam ser abertos individualmente através do comando ALTER PLUGGABLE DATABASE.
  • Existe somente um arquivo de inicialização spfile para todo o CDB. Os PDBs podem ter configurações próprias, mas essas configurações são persistidas no dicionário de dados do Oracle e não em spfiles adicionais para cada PDB criado.
  • Além das views de dicionário de dados DBA/ALL/USER uma nova categoria com o prefixo CDB foi criada para disponibilizar informações e metadados dos bancos de dados PDBs dentro de um CDB.

Em resumo, veremos que o container ROOT (CDB$ROOT) contém as tablespaces SYSTEM, SYSAUX, TEMP, e UNDO além dos control files e redo log files. O SEED container (PDB$SEED) contém as tablespaces SYSTEM, SYSAUX, TEMP (opcional). Vale a pena salientar que este artigo terá com foco apenas a criação dos bancos de dados CDB e PDBs com o objetivo de demonstrar algumas propriedades de sua arquitetura. Demais demonstrações como ações de plugar, desplugar, clonar, alterações de configurações, backups, entre outros, serão apresentados em artigos posteriores.


Criando o banco de dados de container (CDB)

Bom, iniciarei a criação do banco de dados de container CDB01 (sem maiores detalhes) através do utilitário DBCA (Database Configuration Assistant) conforme demonstrado pela figura abaixo:




Após a criação do banco de dados CDB01 poderemos verificar abaixo consultando a view V$DATABASE que o mesmo se trata de um container database. Realizando uma consulta em uma nova view dinâmica de desempenho V$CONTAINER, poderemos verificar que, além do container CDB$ROOT, também temos um seed container chamado PDB$SEED. Através do resultado da view V$PDBS iremos notar que o banco de dados PDB$SEED é somente leitura. O propósito do mesmo é servir como um template para criação de novos PDBs. Consultando a view DBA_PDBS podemos verificar que o mesmo se encontra aberto.

C:\>sqlplus / as sysdba

SQL*Plus: Release 12.1.0.1.0 Production on Seg Fev 3 18:45:39 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 name,cdb,con_id,con_dbid from v$database;

NAME           CDB     CON_ID   CON_DBID
-------------- --- ---------- ----------
CDB01          YES          0 1370556575

SQL> select con_id, name from v$containers;

    CON_ID NAME
---------- --------------------------
         1 CDB$ROOT
         2 PDB$SEED

SQL> select name, open_mode from v$pdbs;

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

SQL> select pdb_id,pdb_name,dbid,status from dba_pdbs;

    PDB_ID PDB_NAME             DBID STATUS
---------- -------------- ---------- -------------
         2 PDB$SEED       4076210644 NORMAL
  
Uma outra forma de verificar se um banco de dados é CDB ou não-CDB é verificando o parâmetro de inicialização ENABLE_PLUGGABLE_DATABASE.

SQL> show parameter enable_pluggable_database;

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
enable_pluggable_database            boolean     TRUE
  
Criando o banco de dados PDB com o DBCA

Com o banco de dados de container CDB01 criado, irei criar o primeiro banco de dados plugável através do DBCA. Este banco de dados terá o nome de PDB01 conforme demonstrado pelas figuras abaixo:

  


     



Criando o banco de dados PDB manualmente com o SQL*Plus

Podemos também criar bancos de dados plugáveis manualmente através do comando CREATE PLUGGABLE DATABASE. Utilizarei o SQL*Plus para criar o banco de dados PDB02 conforme demonstração abaixo:

SQL> create pluggable database PDB02
  2  admin user pdb_admin identified by manager
  3  file_name_convert =
  4  (
  5  'D:\oracle\app\oradata\CDB01\pdbseed',
  6  'D:\oracle\app\oradata\CDB01\PDB02'
  7  );

Banco de dados plugável criado.  

Após a criação dos bancos de dados plugáveis PDB01 e PDB02, irei comentar abaixo sobre algumas peculiaridades dos mesmos.

SQL> select a.con_id,
  2         a.name,
  3         a.dbid,
  4         b.status,
  5         a.open_mode,
  6         a.total_size
  7  from v$pdbs a, dba_pdbs b
  8  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 NEW           MOUNTED             0

No resultado da query acima, podemos verificar que o banco de dados plugável PDB$SEED é por padrão somente leitura e que o banco PBD02 encontra-se no estado NEW e no modo MOUNT. Diferentemente de utilizar o DBCA, que já faz o trabalho de abrir o banco plugável no modo de escrita/gravação, quando criamos um banco de dados plugável manualmente, precisaremos realizar o procedimento abaixo para deixá-lo no modo de escrita/gravação.

SQL> alter pluggable database PDB02 open read write;

Banco de dados plugável alterado.
  
Para facilitar o entendimento da arquitetura física dos arquivos de banco de dados envolvidos, segue abaixo a hierarquia dos diretórios criados após a criação dos bancos de dados:

D:\oracle\app\oradata> tree /F /A

D:.
\---CDB01
    |   CONTROL01.CTL
    |   CONTROL02.CTL
    |   REDO01.LOG
    |   REDO02.LOG
    |   REDO03.LOG
    |   SYSAUX01.DBF
    |   SYSTEM01.DBF
    |   TEMP01.DBF
    |   UNDOTBS01.DBF
    |   USERS01.DBF
    |
    +---PDB01
    |       PDB01_USERS01.DBF
    |       PDBSEED_TEMP01.DBF
    |       SYSAUX01.DBF
    |       SYSTEM01.DBF
    |
    +---PDB02
    |       PDBSEED_TEMP01.DBF
    |       SYSAUX01.DBF
    |       SYSTEM01.DBF
    |
    \---pdbseed
            PDBSEED_TEMP01.DBF
            SYSAUX01.DBF
            SYSTEM01.DBF

Podemos verificar também que os bancos de dados se registraram no LISTENER com sucesso. Segue abaixo a saída do comando "lsnrctl status".

C:\>lsnrctl status

LSNRCTL for 64-bit Windows: Version 12.1.0.1.0 - Production on 03-FEV-2014 18:50:05

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

Estabelecendo conexão com (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=PChome)(PORT=1521)))
STATUS do LISTENER
------------------------
Apelido              LISTENER
Versão               TNSLSNR for 64-bit Windows: Version 12.1.0.1.0 - Production
Data Inicial         03-FEV-2014 18:50:41
Funcionamento        0 dias 1 hr. 36 min. 27 seg
Nível de Análise     off
Segurança            ON: Local OS Authentication
SNMP                 OFF
Arq. Parâm. Listn.   D:\oracle\app\product\12.1.0\dbhome_1\network\admin\listener.ora
Arq. Log Listener    D:\oracle\app\diag\tnslsnr\PChome\listener\alert\log.xml
Resumo de Atendimento...
  (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=PChome)(PORT=1521)))
  (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(PIPENAME=\\.\pipe\EXTPROC1521ipc)))
Resumo de Serviços...
O serviço "CDB01" tem 1 instância(s).
  Instância "cdb01", status READY, tem 1 handler(s) para este serviço...
O serviço "CDB01XDB" tem 1 instância(s).
  Instância "cdb01", status READY, tem 1 handler(s) para este serviço...
O serviço "CLRExtProc" tem 1 instância(s).
  Instância "CLRExtProc", status UNKNOWN, tem 1 handler(s) para este serviço...
O serviço "pdb01" tem 1 instância(s).
  Instância "cdb01", status READY, tem 1 handler(s) para este serviço...
O serviço "pdb02" tem 1 instância(s).
  Instância "cdb01", status READY, tem 1 handler(s) para este serviço...
O comando foi executado com êxito
  
A view dinâmica de desempenho V$SERVICES também pode ser utilizada para obter informações dos serviços de bancos de dados disponíveis como demonstrado abaixo:

SQL> select name,pdb from v$services;

NAME            PDB
--------------- ------------------------------
CDB01           CDB$ROOT
CDB01XDB        CDB$ROOT
pdb01           PDB01
pdb02           PDB02
SYS$BACKGROUND  CDB$ROOT
SYS$USERS       CDB$ROOT

6 linhas selecionadas. 
 

Navegando entre containers (CDB e PDBs)

Por padrão, quando conectamos no banco de dados como SYSDBA sem informar um serviço TNS, iremos nos conectar no container ROOT. Conectar no container ROOT é o mesmo que conectar em um banco de dados não-CDB como fazemos quando conectamos em um banco de dados de versões anteriores como o Oracle 11g ou 10g. Para confirmar isso, ou seja, mostrar o container corrente, é possível utilizar o comando SHOW CON_NAME do SQL*Plus conforme demonstrado a seguir:

SQL> show con_name

CON_NAME
------------------------------
CDB$ROOT 
  
Ao consultar a view de dicionário de dados DBA_DATA_FILES abaixo, podemos confirmar que os arquivos de dados (data files) mostrados são provenientes do banco de dados CDB01.

SQL> select file_id,file_name from dba_data_files;

   FILE_ID FILE_NAME
---------- ------------------------------------------------
         1 D:\ORACLE\APP\ORADATA\CDB01\SYSTEM01.DBF
         3 D:\ORACLE\APP\ORADATA\CDB01\SYSAUX01.DBF
         5 D:\ORACLE\APP\ORADATA\CDB01\UNDOTBS01.DBF
         6 D:\ORACLE\APP\ORADATA\CDB01\USERS01.DBF


Para navegarmos entre os containers existentes, poderemos executar o comando ALTER SESSION SET CONTAINER conforme demonstrado abaixo:

SQL> alter session set container = PDB01;

Sessão alterada.

SQL> show con_name

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

SQL> select file_id,file_name from dba_data_files;

   FILE_ID FILE_NAME
---------- -----------------------------------------------------
         7 D:\ORACLE\APP\ORADATA\CDB01\PDB01\SYSTEM01.DBF
         8 D:\ORACLE\APP\ORADATA\CDB01\PDB01\SYSAUX01.DBF
         9 D:\ORACLE\APP\ORADATA\CDB01\PDB01\PDB01_USERS01.DBF

SQL> alter session set container = CDB$ROOT;

Sessão alterada.

SQL> show con_name

CON_NAME
------------------------------
CDB$ROOT 
  
Realizando STARTUP e SHUTDOWN dos bancos de dados

Se quisermos realizar o shutdown de um banco de dados PDB específico, será necessário utilizar o comando ALTER PLUGGABLE DATABASE ... CLOSE IMMEDIATE conforme exemplo abaixo:

SQL> alter pluggable database PDB01 close immediate;

Banco de dados plugável alterado.
 
Para realizar a opção inversa, ou seja, abrir o banco de dados para leitura/escrita bastará utilizar o comando ALTER PLUGGABLE DATABASE ... OPEN conforme demonstrado a seguir:

SQL> alter pluggable database PDB01 open;

Banco de dados plugável alterado.
  

Uma observação importante que notei, está relacionado à inicialização dos bancos de dados PDBs quando realizamos o startup do banco de dados CDB. Não há um mecanismo default que inicializa automaticamente os bancos de dados PDBs quando o banco de dados CDB é inicializado. Poderemos ver abaixo que, ao realizar o startup do banco de dados CDB (CDB01), todos os bancos de dados PDBs (PDB01 e PDB02) permanecem no estado MOUNT.

C:\>sqlplus / as sysdba

SQL*Plus: Release 12.1.0.1.0 Production on Seg Fev 3 19:00:47 2014

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

Conectado a uma instância inativa.

SQL> startup
Instância ORACLE iniciada.

Total System Global Area 1068937216 bytes
Fixed Size                  2410864 bytes
Variable Size             373294736 bytes
Database Buffers          687865856 bytes
Redo Buffers                5365760 bytes
Banco de dados montado.
Banco de dados aberto.

SQL> select a.con_id,
  2         a.name,
  3         a.dbid,
  4         b.status,
  5         a.open_mode,
  6         a.total_size
  7  from v$pdbs a, dba_pdbs b
  8  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        MOUNTED             0
         4 PDB02           3947824578 NEW           MOUNTED             0

Para realizar o startup de todos os bancos de dados PDBs de uma única vez, poderemos executar o comando ALTER PLUGGABLE DATABASE ALL OPEN conforme demonstrado a seguir:

SQL> alter pluggable database all open;

Banco de dados plugável alterado.
 
Para evitar que precisemos executar o comando acima todas as vezes que inicializamos a instância CDB, poderemos criar uma trigger de banco de dados chamando o evento AFTER STARTUP ON DATABASE conforme exemplo abaixo:

SQL> create or replace trigger open_all_pdbs
  2  after startup on database
  3  begin
  4     execute immediate 'alter pluggable database all open';
  5  end open_all_pdbs;
  6  /

Gatilho criado.
 

Conectando nos bancos de dados (CDB e PDBs)

Em relação à conexão com os bancos de dados, sejam eles CDBs ou PDBs, os mesmos podem ser acessados da mesma forma que nas versões anteriores, seja utilizando o arquivo TNSNAMES.ora, seja utilizando via o método Easy Connect (EZCONNECT) conforme demonstrado nos exemplos a seguir:

  • sqlplus system/manager@localhost:1521/CDB01
  • sqlplus system/manager@localhost:1521/PDB01
  • sqlplus system/manager@localhost:1521/PDB02

Um dado interessante é que, ao conectarmos a um banco de dados PDB e consultarmos a view de dicionário de dados V$DATABASE, veremos que será mostrado o banco de dados CDB, e não o banco de dados PDB conforme demonstrado abaixo:

C:\>sqlplus system/manager@localhost:1521/PDB01

SQL*Plus: Release 12.1.0.1.0 Production on Ter Fev 3 19:15:00 2014

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

Horário do último log-in bem-sucedido: Ter Fev 3 2014 19:12:04 -02:00

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 name from v$database;

NAME
----------------------
CDB01 
  
O exemplo acima nos demonstra de forma mais clara o conceito de containers dentro da arquitetura Multitenant do Oracle 12c. Abaixo podemos verificar através do comando do SQL*Plus SHOW CON_NAME que o container corrente é o PDB01.

SQL> show con_name;

CON_NAME
------------------------------
PDB01  
 
Se quisermos obter o container corrente através de uma instrução SQL, poderemos utilizar a função SYS_CONTEXT conforme exemplo a seguir:

SQL> select sys_context('userenv','con_name') from dual;

SYS_CONTEXT('USERENV','CON_NAME')
---------------------------------
PDB01 
 
Criando usuários comuns e usuário locais

Em relação à criação de usuários no bancos de dados CDBs e PDBs, existe um conceito novo na arquitetura Multitenant do Oracle 12c. Nesse ambiente existem dois tipos de usuários: Usuários comuns (Common Users) e usuários locais (Local Users). Usuários comuns estão presentes em todos os containers (ROOT e PDBs). Já os usuários locais só estão presentes em seus PDBs específicos. Um mesmo usuário local pode existir em mais de um PDB, mas eles não tem qualquer relação um com o outro.

Da mesma forma que existem usuários comuns e locais, também existem roles comuns (Common Roles) e roles locais (Local Roles). Todo o banco de dados CDB possui um ambiente de usuários comuns. Um usuário que existe no container ROOT pode se conectar em qualquer PDB com os privilégios apropriados e, por padrão, são mapeados para todos os PDBs atuais e aos PDBs criados futuramente. Um usuário comum não pode ser criado em um banco de dados PDB, somente em um CDB. Os usuários comuns precisam ser criados utilizando o prefixo C## ou c##. Já os usuários locais podem somente ser criados nos PDBs. Veja o exemplo abaixo:

C:\>sqlplus system/manager@localhost/PDB01

SQL*Plus: Release 12.1.0.1.0 Production on Seg Fev 3 19:20:16 2014

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

Horário do último log-in bem-sucedido: Seg Fev 03 2014 19:19:16 -02:00

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 user scott identified by tiger;

Usuário criado.

SQL> grant create session to scott;

Concessão bem-sucedida. 
 
Acima, eu conectei no banco de dados PDB01 e criei o usuário local SCOTT. Ao consultar a view de dicionário de dados ALL_USERS, poderemos ver abaixo que tanto o usuário SCOTT quanto o usuário PDB_ADMIN (criado durante a criação do banco de dados PDB01), possuem o valor "NO" na coluna COMMON, o que significa que os mesmos são usuários locais do banco de dados PDB01.

SQL> select username,common from all_users where common='NO';

USERNAME                   COM
-------------------------- ---
PDB_ADMIN                   NO
SCOTT                       NO
 
Abaixo irei criar um usuário comum no banco de dados CDB. Podemos verificar abaixo que se tentarmos criar um usuário comum se usar o prefixo C## o erro ORA-65096 será emitido.

C:\>sqlplus system/manager@localhost/CDB01

SQL> create user global identified by global;
create user global identified by global
            *
ERRO na linha 1:
ORA-65096: nome de atribuição ou de usuário comum inválido

SQL> create user c##global identified by global;

Usuário criado.
 
Após a criação do usuário comum C##GLOBAL, irei conceder o privilégio CREATE SESSION de forma que o mesmo possa se conectar tanto no banco de dados CDB01 quanto nos bancos de dados PDBs através da cláusula CONTAINER=ALL do comando GRANT.

SQL> grant create session to c##global;

Concessão bem-sucedida.

SQL> grant create session to c##global container=ALL;

Concessão bem-sucedida.  

Após a concessão do privilégio CREATE SESSION em conjunto com a opção CONTAINER=ALL para o usuário comum C##GLOBAL, poderemos verificar abaixo que a conexão com o banco de dados PDB02, por exemplo, será realizada com sucesso.

C:\>sqlplus C##global/global@localhost/PDB02

SQL*Plus: Release 12.1.0.1.0 Production on Ter Fev 3 19:30:56 2014

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

Horário do último log-in bem-sucedido: Seg Fev 3 2014 19:25:24 -02:00

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 user;
USER é "C##GLOBAL"

SQL> show con_name;

CON_NAME
------------------------------
PDB02


Resumo

Para ilustrar um pouco do que foi demonstrado nesse artigo, segue abaixo uma figura que resume bem o conceito por trás da arquitetura Multitenant do Oracle 12c.



Para finalizar, segue abaixo alguns exemplos das opções que temos para abrir (startup) e fechar (shutdown) um banco de dados plugável no Oracle 12c. Em alguns dos exemplos, entenda o caractere | (pipe) como ENTER.


-- startup
  • alter pluggable database PDB01 open;
  • alter pluggable database PDB01 open read only;
  • alter pluggable database PDB01, PDB02 open;
  • alter pluggable database all open;
  • startup pluggable database PDB01;
  • alter session set container=PDB01; | startup

-- shutdown

  • alter pluggable database PDB01 close immediate;
  • alter pluggable database all close immediate;
  • alter pluggable database all except PDB02 close immediate;
  • sqlplus sys@PDB01 as sysdba | shutdown immediate;

quinta-feira, 2 de janeiro de 2014

Movendo tabelas, índices e segmentos LOB para tablespaces distintas no Oracle

Por Eduardo Legatti

Olá,

Como já mencionado no artigo de Março/2008 na qual eu faço uma breve introdução ao conceito de tablespaces no Oracle, um banco de dados Oracle consiste em uma ou mais unidades de armazenamento lógicas denominadas tablespaces, que armazenam coletivamente todos os dados do banco de dados. Cada tablespace em um banco de dados Oracle consiste em um ou mais arquivos denominados arquivos de dados (data files), que são estruturas físicas compatíveis com o sistema operacional no qual o Oracle é executado. Vale a pena salientar que os arquivos de banco de dados também podem ser criados utilizando o ASM (Automatic Storage Manager) que é um gerenciador de volumes e ao mesmo tempo um sistema de arquivos para banco de dados Oracle. Em resumo, os dados de um banco de dados Oracle são armazenados coletivamente nos arquivos de dados que constituem cada tablespace do banco de dados. É aconselhável não misturar dados de aplicativos em um mesmo tablespace. Recomendo que, ao criar tablespaces para seus aplicativos, dê a eles um nome descritivo (por exemplo, dados de um sistema de RH podem ser mantidos no tablespace RECURSOS_HUMANOS). Neste caso, uma aplicação específica poderá ter seus dados separados logicamente de outras aplicações em um mesmo banco de dados. Uma outra vantagem em separar as aplicações em tablespaces distintos seria a oportunidade de utilizar o método Tablespace Point-in-Time Recovery (TSPITR) caso necessário, durante um evento de recover sem prejudicar as demais aplicações. Assim como mencionado no artigo de Junho/2008 sobre a reorganização de tablespaces, irei tratar nesse artigo sobre a organização de segmentos de banco de dados que poderão residir em tablespaces específicos separados das tabelas. Os segmentos são objetos que ocupam espaço em um banco de dados. Existem vários tipos de segmentos como tabelas, índices, segmentos de undo, segmentos temporários, LOB, entre outros. Neste artigo irei tratar especificamente da realocação de índices e segmentos LOB para outros tablespaces. No meu ponto de vista, separar esses segmentos em tablespaces distintos podem trazer alguns benefícios para quem administra o banco de dados.


O cenário que irei criar possui um schema de banco de dados (SCOTT) que possui 3 tabelas contendo várias colunas entre elas colunas do tipo LOB (BLOB, CLOB) além alguns índices. Inicialmente, tanto as tabelas/índices quantos os segmento LOB estão alocados em uma única tablespace TBS_DATA. O objetivo principal será demonstrar como mover não só os segmentos LOB para uma tablespace específica chamada TBS_LOB, como também mover todos os índices para uma tablespace específica chamada TBS_INDX. Ao final, irei demonstrar como mover as tabelas para uma outra tablespace.

C:\>sqlplus scott/tiger

SQL*Plus: Release 11.2.0.1.0 Production on Qui Jan 2 10:15:39 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 * from session_privs;

PRIVILEGE
----------------------------------------
CREATE SESSION
UNLIMITED TABLESPACE
CREATE TABLE
CREATE CLUSTER
CREATE SEQUENCE
CREATE PROCEDURE
CREATE TRIGGER
CREATE TYPE
CREATE OPERATOR
CREATE INDEXTYPE
SELECT ANY DICTIONARY

11 linhas selecionadas.


Acima estou demonstrando que concedi o privilégio de sistema SELECT ANY DICTIONARY para o usuário SCOTT de forma que o mesmo tenha acesso às views de dicionário de dados DBA_*. Abaixo está o resultado dos dados do schema SCOTT separados por tipo de segmento. A consulta SQL utilizada é mesma usada no artigo de Maio/2005 intitulado de "Qual é mesmo o tamanho de uma tabela no Oracle?".

SQL> break on report
SQL> compute sum of data_mb on report
SQL> compute sum of indx_mb on report
SQL> compute sum of lob_mb on report
SQL> compute sum of total_mb on report

SQL> SELECT table_name,
  2         DECODE(partitioned,'/','NO',partitioned) partitioned,
  3         num_rows,
  4         data_mb,
  5         indx_mb,
  6         lob_mb,
  7         total_mb
  8      FROM (SELECT data.table_name,
  9                   partitioning_type
 10                   || DECODE (subpartitioning_type,
 11                              'NONE', NULL,
 12                              '/' || subpartitioning_type)
 13                      partitioned,
 14                   num_rows,
 15                   NVL(data_mb,0) data_mb,
 16                   NVL(indx_mb,0) indx_mb,
 17                   NVL(lob_mb,0) lob_mb,
 18                   NVL(data_mb,0) + NVL(indx_mb,0) + NVL(lob_mb,0) total_mb
 19              FROM (  SELECT table_name,
 20                             NVL(MIN(num_rows),0) num_rows,
 21                             ROUND(SUM(data_mb),2) data_mb
 22                        FROM (SELECT table_name, num_rows, data_mb
 23                                FROM (SELECT a.table_name,
 24                                             a.num_rows,
 25                                             b.bytes/1024/1024 AS data_mb
 26                                        FROM user_tables a, user_segments b
 27                                       WHERE a.table_name = b.segment_name))
 28                    GROUP BY table_name) data,
 29                   (  SELECT a.table_name,
 30                             ROUND(SUM(b.bytes/1024/1024),2) AS indx_mb
 31                        FROM user_indexes a, user_segments b
 32                       WHERE a.index_name = b.segment_name
 33                    GROUP BY a.table_name) indx,
 34                   (  SELECT a.table_name,
 35                             ROUND(SUM(b.bytes/1024/1024),2) AS lob_mb
 36                        FROM user_lobs a, user_segments b
 37                       WHERE a.segment_name = b.segment_name
 38                    GROUP BY a.table_name) lob,
 39                   user_part_tables part
 40             WHERE     data.table_name = indx.table_name(+)
 41                   AND data.table_name = lob.table_name(+)
 42                   AND data.table_name = part.table_name(+))
 43  ORDER BY table_name;

TABLE_NAME     PARTITIONED       NUM_ROWS    DATA_MB    INDX_MB     LOB_MB   TOTAL_MB
-------------- --------------- ---------- ---------- ---------- ---------- ----------
T1             NO                   12000         31       5,25     384,06     420,31
T2             NO                   50000        400      12,13        ,13     412,26
T3             NO                  180000       1472     232,13        ,13    1704,26
                                          ---------- ---------- ---------- ----------
sum                                             1903     249,51     384,32    2536,83

3 linhas selecionadas.


Abaixo estão listados os segmentos de tabela, índices e LOB. Podemos perceber que todos os segmentos estão alocados na tablespace TBS_DATA.

SQL> SELECT owner,
  2         segment_name,
  3         segment_type,
  4         tablespace_name
  5    FROM dba_segments
  6   WHERE owner = 'SCOTT';

OWNER                SEGMENT_NAME                 SEGMENT_TYPE       TABLESPACE_NAME
-------------------- ---------------------------- ------------------ ------------------
SCOTT                T1                           TABLE              TBS_DATA
SCOTT                T2                           TABLE              TBS_DATA
SCOTT                T3                           TABLE              TBS_DATA
SCOTT                IDX_T1_01                    INDEX              TBS_DATA
SCOTT                IDX_T1_02                    INDEX              TBS_DATA
SCOTT                IDX_T1_03                    INDEX              TBS_DATA
SCOTT                IDX_T1_04                    INDEX              TBS_DATA
SCOTT                IDX_T2_01                    INDEX              TBS_DATA
SCOTT                IDX_T2_02                    INDEX              TBS_DATA
SCOTT                IDX_T2_03                    INDEX              TBS_DATA
SCOTT                IDX_T3_01                    INDEX              TBS_DATA
SCOTT                IDX_T3_02                    INDEX              TBS_DATA
SCOTT                SYS_IL0000141649C00005$$     LOBINDEX           TBS_DATA
SCOTT                SYS_IL0000141654C00004$$     LOBINDEX           TBS_DATA
SCOTT                SYS_IL0000141654C00005$$     LOBINDEX           TBS_DATA
SCOTT                SYS_IL0000141644C00004$$     LOBINDEX           TBS_DATA
SCOTT                SYS_IL0000141644C00005$$     LOBINDEX           TBS_DATA
SCOTT                SYS_IL0000141649C00004$$     LOBINDEX           TBS_DATA
SCOTT                SYS_LOB0000141644C00004$$    LOBSEGMENT         TBS_DATA
SCOTT                SYS_LOB0000141644C00005$$    LOBSEGMENT         TBS_DATA
SCOTT                SYS_LOB0000141649C00004$$    LOBSEGMENT         TBS_DATA
SCOTT                SYS_LOB0000141649C00005$$    LOBSEGMENT         TBS_DATA
SCOTT                SYS_LOB0000141654C00004$$    LOBSEGMENT         TBS_DATA
SCOTT                SYS_LOB0000141654C00005$$    LOBSEGMENT         TBS_DATA

24 linhas selecionadas.


Como dito anteriormente, o objetivo será mover os segmentos de índices e de LOBs para as tablespaces TBS_INDX e TBS_LOB respectivamente.


SQL> select tablespace_name,
  2         contents,
  3         extent_management,
  4         segment_space_management
  5    from dba_tablespaces
  6    order by 1;

TABLESPACE_NAME                CONTENTS  EXTENT_MAN SEGMEN
------------------------------ --------- ---------- ------
SYSAUX                         PERMANENT LOCAL      AUTO
SYSTEM                         PERMANENT LOCAL      MANUAL
TBS_DATA                       PERMANENT LOCAL      AUTO
TBS_INDX                       PERMANENT LOCAL      AUTO
TBS_LOB                        PERMANENT LOCAL      AUTO
TEMP                           TEMPORARY LOCAL      MANUAL
UNDOTBS1                       UNDO      LOCAL      MANUAL
USERS                          PERMANENT LOCAL      AUTO

8 linhas selecionadas.


Movendo LOBs


Segue abaixo o comando DDL que deverá ser utilizado para mover um segmento LOB para uma outra tablespace:


ALTER TABLE [Table_Name] MOVE LOB([Column_Name]) store as (TABLESPACE [Tablespace_Name]);


Se caso quisermos mover todos os segmentos LOB de um schema para uma tablespace específica (TBS_LOB), poderemos utilizar a consulta abaixo:
SQL> SELECT   'alter table '
  2           || t.owner
  3           || '.'
  4           || t.table_name
  5           || ' move lob ('
  6           || column_name
  7           || ') store as (tablespace TBS_LOB);' CMD
  8      FROM dba_lobs l, dba_tables t
  9     WHERE     l.owner = t.owner
 10           AND l.table_name = t.table_name
 11           AND l.SEGMENT_NAME IN
 12                  (SELECT segment_name
 13                     FROM dba_segments
 14                    WHERE segment_type = 'LOBSEGMENT'
 15                          AND tablespace_name = 'TBS_DATA')
 16           AND l.owner = 'SCOTT'
 17  ORDER BY t.owner, t.table_name;

CMD
----------------------------------------------------------------------
alter table SCOTT.T1 move lob (IMAGEM) store as (tablespace TBS_LOB);
alter table SCOTT.T1 move lob (SUMARIO) store as (tablespace TBS_LOB);
alter table SCOTT.T2 move lob (FOTO) store as (tablespace TBS_LOB);
alter table SCOTT.T2 move lob (SUMARIO) store as (tablespace TBS_LOB);
alter table SCOTT.T3 move lob (IMG_01) store as (tablespace TBS_LOB);
alter table SCOTT.T3 move lob (SAT_01) store as (tablespace TBS_LOB);

6 linhas selecionadas.


Agora irei executar o resultado da consulta afim de mover todos os segmentos LOB para a tablespace TBS_LOB.

SQL> set timing on
SQL> alter table SCOTT.T1 move lob (IMAGEM) store as (tablespace TBS_LOB);

Tabela alterada.

Decorrido: 00:00:00.89
SQL> alter table SCOTT.T1 move lob (SUMARIO) store as (tablespace TBS_LOB);

Tabela alterada.

Decorrido: 00:00:23.24
SQL> alter table SCOTT.T2 move lob (FOTO) store as (tablespace TBS_LOB);

Tabela alterada.

Decorrido: 00:00:31.92
SQL> alter table SCOTT.T2 move lob (SUMARIO) store as (tablespace TBS_LOB);

Tabela alterada.

Decorrido: 00:00:28.93
SQL> alter table SCOTT.T3 move lob (IMG_01) store as (tablespace TBS_LOB);

Tabela alterada.

Decorrido: 00:01:48.34
SQL> alter table SCOTT.T3 move lob (SAT_01) store as (tablespace TBS_LOB);

Tabela alterada.

Decorrido: 00:02:39.70


Movendo Índices


Segue abaixo o comando DDL que deverá ser utilizado para mover um índice para uma outra tablespace:


ALTER INDEX [Index_Name] REBUILD TABLESPACE [Tablespace_Name];


Se caso quisermos mover todos os segmentos de índices de um schema para uma tablespace específica (TBS_INDX), poderemos utilizar a consulta abaixo:
SQL> SELECT ' alter index '
  2         || owner
  3         || '.'
  4         || index_name
  5         || ' rebuild tablespace TBS_INDX;' CMD
  6    FROM dba_indexes
  7   WHERE index_type <> 'LOB' AND owner = 'SCOTT';

CMD
---------------------------------------------------------
 alter index SCOTT.IDX_T1_01 rebuild tablespace TBS_INDX;
 alter index SCOTT.IDX_T1_02 rebuild tablespace TBS_INDX;
 alter index SCOTT.IDX_T1_03 rebuild tablespace TBS_INDX;
 alter index SCOTT.IDX_T1_04 rebuild tablespace TBS_INDX;
 alter index SCOTT.IDX_T2_01 rebuild tablespace TBS_INDX;
 alter index SCOTT.IDX_T2_02 rebuild tablespace TBS_INDX;
 alter index SCOTT.IDX_T2_03 rebuild tablespace TBS_INDX;
 alter index SCOTT.IDX_T3_01 rebuild tablespace TBS_INDX;
 alter index SCOTT.IDX_T3_02 rebuild tablespace TBS_INDX;

9 linhas selecionadas.


Agora irei executar o resultado da consulta afim de mover todos os segmentos de índices para a tablespace TBS_INDX.

SQL>  alter index SCOTT.IDX_T1_01 rebuild tablespace TBS_INDX;

Índice alterado.

Decorrido: 00:00:00.41
SQL>  alter index SCOTT.IDX_T1_02 rebuild tablespace TBS_INDX;

Índice alterado.

Decorrido: 00:00:00.05
SQL>  alter index SCOTT.IDX_T1_03 rebuild tablespace TBS_INDX;

Índice alterado.

Decorrido: 00:00:00.05
SQL>  alter index SCOTT.IDX_T1_04 rebuild tablespace TBS_INDX;

Índice alterado.

Decorrido: 00:00:00.06
SQL>  alter index SCOTT.IDX_T2_01 rebuild tablespace TBS_INDX;

Índice alterado.

Decorrido: 00:00:00.45
SQL>  alter index SCOTT.IDX_T2_02 rebuild tablespace TBS_INDX;

Índice alterado.

Decorrido: 00:00:00.52
SQL>  alter index SCOTT.IDX_T2_03 rebuild tablespace TBS_INDX;

Índice alterado.

Decorrido: 00:00:00.53
SQL>  alter index SCOTT.IDX_T3_01 rebuild tablespace TBS_INDX;

Índice alterado.

Decorrido: 00:00:10.92
SQL>  alter index SCOTT.IDX_T3_02 rebuild tablespace TBS_INDX;

Índice alterado.

Decorrido: 00:00:11.91

Após a realocação dos segmentos de LOB e de índices, podemos ver abaixo como ficou o layout do banco de dados.

SQL> SELECT owner,
  2         segment_name,
  3         segment_type,
  4         tablespace_name
  5    FROM dba_segments
  6   WHERE owner = 'SCOTT';

OWNER                SEGMENT_NAME                 SEGMENT_TYPE       TABLESPACE_NAME
-------------------- ---------------------------- ------------------ ------------------
SCOTT                T1                           TABLE              TBS_DATA
SCOTT                T2                           TABLE              TBS_DATA
SCOTT                T3                           TABLE              TBS_DATA
SCOTT                IDX_T1_01                    INDEX              TBS_INDX
SCOTT                IDX_T1_02                    INDEX              TBS_INDX
SCOTT                IDX_T1_03                    INDEX              TBS_INDX
SCOTT                IDX_T1_04                    INDEX              TBS_INDX
SCOTT                IDX_T2_01                    INDEX              TBS_INDX
SCOTT                IDX_T2_02                    INDEX              TBS_INDX
SCOTT                IDX_T2_03                    INDEX              TBS_INDX
SCOTT                IDX_T3_01                    INDEX              TBS_INDX
SCOTT                IDX_T3_02                    INDEX              TBS_INDX
SCOTT                SYS_IL0000141649C00005$$     LOBINDEX           TBS_LOB
SCOTT                SYS_IL0000141654C00004$$     LOBINDEX           TBS_LOB
SCOTT                SYS_IL0000141654C00005$$     LOBINDEX           TBS_LOB
SCOTT                SYS_IL0000141644C00004$$     LOBINDEX           TBS_LOB
SCOTT                SYS_IL0000141644C00005$$     LOBINDEX           TBS_LOB
SCOTT                SYS_IL0000141649C00004$$     LOBINDEX           TBS_LOB
SCOTT                SYS_LOB0000141644C00004$$    LOBSEGMENT         TBS_LOB
SCOTT                SYS_LOB0000141644C00005$$    LOBSEGMENT         TBS_LOB
SCOTT                SYS_LOB0000141649C00004$$    LOBSEGMENT         TBS_LOB
SCOTT                SYS_LOB0000141649C00005$$    LOBSEGMENT         TBS_LOB
SCOTT                SYS_LOB0000141654C00004$$    LOBSEGMENT         TBS_LOB
SCOTT                SYS_LOB0000141654C00005$$    LOBSEGMENT         TBS_LOB

24 linhas selecionadas.


Movendo tabelas


Para finalizar, caso seja necessário mover alguma tabela para uma outra tablespace, o comando DDL abaixo deverá ser utilizado para fazer esse trabalho:

ALTER TABLE [Table_Name] MOVE TABLESPACE [Tablespace_Name]; 





Como exemplo, irei mover todas as tabelas do schema SCOTT para a tablespace USERS.

SQL> SELECT ' alter table '
  2         || owner
  3         || '.'
  4         || table_name
  5         || ' move tablespace USERS;' CMD
  6    FROM dba_tables
  7   WHERE owner = 'SCOTT';

CMD
--------------------------------------------
 alter table SCOTT.T1 move tablespace USERS;
 alter table SCOTT.T2 move tablespace USERS;
 alter table SCOTT.T3 move tablespace USERS;

3 linhas selecionadas.

SQL>  alter table SCOTT.T3 move tablespace USERS;

Tabela alterada.

Decorrido: 00:01:43.42
SQL>  alter table SCOTT.T2 move tablespace USERS;

Tabela alterada.

Decorrido: 00:00:33.89
SQL>  alter table SCOTT.T1 move tablespace USERS;

Tabela alterada.

Decorrido: 00:00:01.45

Após a realocação das tabelas para uma outra tablespace (USERS), poderemos notar que todos os índices das tabelas envolvidas, ficaram inválidos (UNUSABLE). Isso ocorreu devido a alteração dos ROWIDs das linhas das tabelas durante o processo de movimentação. Para corrigir esse problema, termos que reconstruir todos os índices envolvidos. 

SQL> SELECT owner, index_name, status, tablespace_name
  2    FROM dba_indexes
  3   WHERE owner = 'SCOTT' AND status <> 'VALID';

OWNER                      INDEX_NAME                STATUS     TABLESPACE_NAME
-------------------------- ------------------------- ---------- ------------------
SCOTT                      IDX_T1_01                 UNUSABLE   TBS_INDX
SCOTT                      IDX_T1_02                 UNUSABLE   TBS_INDX
SCOTT                      IDX_T1_03                 UNUSABLE   TBS_INDX
SCOTT                      IDX_T1_04                 UNUSABLE   TBS_INDX
SCOTT                      IDX_T2_01                 UNUSABLE   TBS_INDX
SCOTT                      IDX_T2_02                 UNUSABLE   TBS_INDX
SCOTT                      IDX_T2_03                 UNUSABLE   TBS_INDX
SCOTT                      IDX_T3_01                 UNUSABLE   TBS_INDX
SCOTT                      IDX_T3_02                 UNUSABLE   TBS_INDX

9 linhas selecionadas.

SQL> SELECT ' alter index ' 
  2         || owner 
  3         || '.' 
  4         || index_name 
  5         || ' rebuild;' CMD
  6    FROM dba_indexes
  7   WHERE owner = 'SCOTT' AND status <> 'VALID';

CMD
-------------------------------------
 alter index SCOTT.IDX_T1_01 rebuild;
 alter index SCOTT.IDX_T1_02 rebuild;
 alter index SCOTT.IDX_T1_03 rebuild;
 alter index SCOTT.IDX_T1_04 rebuild;
 alter index SCOTT.IDX_T2_01 rebuild;
 alter index SCOTT.IDX_T2_02 rebuild;
 alter index SCOTT.IDX_T2_03 rebuild;
 alter index SCOTT.IDX_T3_01 rebuild;
 alter index SCOTT.IDX_T3_02 rebuild;

9 linhas selecionadas.


Após a execução da consulta acima, irei executar o resultado da mesma afim de reconstruir todos os índices que ficaram inválidos.

SQL>  alter index SCOTT.IDX_T1_01 rebuild;

Índice alterado.

Decorrido: 00:00:00.20
SQL>  alter index SCOTT.IDX_T1_02 rebuild;

Índice alterado.

Decorrido: 00:00:00.06
SQL>  alter index SCOTT.IDX_T1_03 rebuild;

Índice alterado.

Decorrido: 00:00:00.05
SQL>  alter index SCOTT.IDX_T1_04 rebuild;

Índice alterado.

Decorrido: 00:00:00.07
SQL>  alter index SCOTT.IDX_T2_01 rebuild;

Índice alterado.

Decorrido: 00:00:00.46
SQL>  alter index SCOTT.IDX_T2_02 rebuild;

Índice alterado.

Decorrido: 00:00:00.50
SQL>  alter index SCOTT.IDX_T2_03 rebuild;

Índice alterado.

Decorrido: 00:00:00.59
SQL>  alter index SCOTT.IDX_T3_01 rebuild;

Índice alterado.

Decorrido: 00:00:19.43
SQL>  alter index SCOTT.IDX_T3_02 rebuild;

Índice alterado.

Decorrido: 00:00:10.50


Pronto. Por fim, poderemos verificar abaixo que todas as tabelas foram realocadas para a tablespace USERS.

SQL> SELECT owner,
  2         segment_name,
  3         segment_type,
  4         tablespace_name
  5    FROM dba_segments
  6   WHERE owner = 'SCOTT';

OWNER                SEGMENT_NAME                 SEGMENT_TYPE       TABLESPACE_NAME
-------------------- ---------------------------- ------------------ ------------------
SCOTT                T1                           TABLE              USERS
SCOTT                T2                           TABLE              USERS
SCOTT                T3                           TABLE              USERS
SCOTT                IDX_T1_01                    INDEX              TBS_INDX
SCOTT                IDX_T1_02                    INDEX              TBS_INDX
SCOTT                IDX_T1_03                    INDEX              TBS_INDX
SCOTT                IDX_T1_04                    INDEX              TBS_INDX
SCOTT                IDX_T2_01                    INDEX              TBS_INDX
SCOTT                IDX_T2_02                    INDEX              TBS_INDX
SCOTT                IDX_T2_03                    INDEX              TBS_INDX
SCOTT                IDX_T3_01                    INDEX              TBS_INDX
SCOTT                IDX_T3_02                    INDEX              TBS_INDX
SCOTT                SYS_IL0000141649C00005$$     LOBINDEX           TBS_LOB
SCOTT                SYS_IL0000141654C00004$$     LOBINDEX           TBS_LOB
SCOTT                SYS_IL0000141654C00005$$     LOBINDEX           TBS_LOB
SCOTT                SYS_IL0000141644C00004$$     LOBINDEX           TBS_LOB
SCOTT                SYS_IL0000141644C00005$$     LOBINDEX           TBS_LOB
SCOTT                SYS_IL0000141649C00004$$     LOBINDEX           TBS_LOB
SCOTT                SYS_LOB0000141644C00004$$    LOBSEGMENT         TBS_LOB
SCOTT                SYS_LOB0000141644C00005$$    LOBSEGMENT         TBS_LOB
SCOTT                SYS_LOB0000141649C00004$$    LOBSEGMENT         TBS_LOB
SCOTT                SYS_LOB0000141649C00005$$    LOBSEGMENT         TBS_LOB
SCOTT                SYS_LOB0000141654C00004$$    LOBSEGMENT         TBS_LOB
SCOTT                SYS_LOB0000141654C00005$$    LOBSEGMENT         TBS_LOB

24 linhas selecionadas.

Postagens populares