domingo, 4 de dezembro de 2011

Um pouco sobre índices particionados no Oracle ...

Olá,

Em artigos anteriores como os de Fevereiro/2011, Abril/2011 e Junho/2011 apresentei uma visão geral sobre tabelas particionadas. A idéia deste artigo é demonstrar os tipos de índices que podemos criar sobre as tabelas particionadas, como os índices particionados globais e locais, além dos índices globais não particionados.


Bom, de forma geral, o objetivo de um índice é permitir acesso mais rápido às linhas de uma tabela. Um índice armazena o valor da coluna ou colunas que estão sendo indexadas, junto com o ROWID da linha que contém o valor indexado. A figura abaixo representa um índice comum ou regular (Btree) criado sobre uma tabela não particionada.
Em se tratando de tabelas particionadas, podemos criar índices locais e globais, ambos particionados e também poderemos criar índices globais não particionados. Para este artigo criarei a tabela T1 particionada por faixa (RANGE) como demonstrado abaixo:

SQL> create table t1
  2    (id  number,
  3     cod number)
  3     tablespace users
  4     partition by range(id)
  5      (
  6       partition pdezenas  values less than (100)  tablespace tbs_dezenas,
  7       partition pcentenas values less than (1000) tablespace tbs_centenas,
  8       partition pmilhares_1000 values less than (2000)  tablespace tbs_milhares,
  9       partition pmilhares_2000 values less than (3000)  tablespace tbs_milhares,
 10       partition pmilhares_3000 values less than (4000)  tablespace tbs_milhares,
 11       partition pmilhares_4000 values less than (5000)  tablespace tbs_milhares,
 12       partition pmilhares_n values less than (maxvalue) tablespace tbs_milhares
 13    );

Tabela criada.


Bom, os índices particionados locais refletem a estrutura da tabela particionada e são particionados de forma igual a tabela particionada subjacente, ou seja, eles são particionados nas mesmas colunas que a tabela e, portanto, tem os mesmos números de partições e os mesmos limites (HIGH_VALUE) que a tabela particionada. Vale a pena salientar que as partições de índices recebem o mesmo nome das partições de tabela. Um dos benefícios dos índice locais é a sua afinidade com a tabela subjacente, pois quando uma nova partição é criada, a partição de índice correspondente é criada automaticamente. Da mesma maneira, ao dropar uma partição da tabela, a partição de índice também é dropada automaticamente sem invalidar quaisquer outras partições de índice, como seria no caso de um índice global. A figura abaixo representa um índice particionado localmente.



SQL> create index idx_t1_local on t1 (id) local;

Índice criado.

SQL> select index_name,
  2         partition_name,
  3         high_value,
  4         tablespace_name
  5    from user_ind_partitions;

INDEX_NAME         PARTITION_NAME           HIGH_VALUE TABLESPACE_NAME
------------------ ------------------------ ---------- ------------------------
IDX_T1_LOCAL       PDEZENAS                 100        TBS_DEZENAS
IDX_T1_LOCAL       PCENTENAS                1000       TBS_CENTENAS
IDX_T1_LOCAL       PMILHARES_1000           2000       TBS_MILHARES
IDX_T1_LOCAL       PMILHARES_2000           3000       TBS_MILHARES
IDX_T1_LOCAL       PMILHARES_3000           4000       TBS_MILHARES
IDX_T1_LOCAL       PMILHARES_4000           5000       TBS_MILHARES
IDX_T1_LOCAL       PMILHARES_N              MAXVALUE   TBS_MILHARES


Podemos também criar índices únicos locais, mas para isso a coluna chave de partição precisa obrigatoriamente fazer parte do índice, diferentemente dos índices globais não particionados. Se tentarmos criar um índice único local sem a coluna chave da partição, então o erro ORA-14039 será emitido:

SQL> create unique index idx_t1_local on t1 (cod) local;
create unique index idx_t1_local on t1 (cod) local 
*ERRO na linha 1:ORA-14039: colunas particionadas devem formar um subconjunto de
colunas de chaves de um índice UNIQUE


Abaixo podemos ver que o índice será criado somente se a coluna chave da partição estiver presente:

SQL> create unique index idx_t1_local on t1 (id,cod) local;

Índice criado.


Já os índices particionados globais não precisam ser necessariamente particionados da mesma maneira que a tabela subjacente. A figura abaixo mostra claramente que o número de partições na tabela pode ou não, ser igual ao número de partições do índice.



Dependendo das operações DDL executadas nas partições da tabela (ADD, DROP, MOVE, TRUNCATE, SPLIT, MERGE, EXCHANGE ...) um índice global poderá ficar marcado como inutilizável (unusable). Portanto, utilizar a cláusula UPDATE GLOBAL INDEXES é uma boa prática:

SQL> ALTER TABLE ... DROP PARTITION P1 UPDATE GLOBAL INDEXES;
SQL> TRUNCATE TABLE ... UPDATE GLOBAL INDEXES;
SQL> ALTER TABLE ... DROP PARTITION P1 UPDATE GLOBAL INDEXES;


No caso de índices globais, para que o mesmo seja criado, ele deverá ser prefixado, ou seja, a coluna chave de partição precisará fazer parte do índice, caso contrário o erro ORA-14038: índice GLOBAL particionado deve ser prefixado será emitido. É importante frisar também que no caso de índices globais, criar uma partição com o limite (MAXVALUE) é obrigatória, caso contrário o erro ORA-14021 será emitido como demonstrado abaixo:

SQL> create index idx_t1_global on t1 (id)
  2  tablespace users
  3  global partition by range (id)
  4  (partition idxp_1500 values less than(1500),
  5   partition idxp_2900 values less than(2900),
  6   partition idxp_4600 values less than(4600),
  7   partition idxp_5000 values less than(5000));
 partition idxp_5000 values less than(5000))
*ERRO na linha 6:ORA-14021: MAXVALUE deve ser especificado para todas as colunas

SQL> create index idx_t1_global on t1 (id)
  2  tablespace users
  3  global partition by range (id)
  4  (partition idxp_1500 values less than(1500),
  5   partition idxp_2900 values less than(2900),
  6   partition idxp_4600 values less than(4600),
  7   partition idxp_5000 values less than(5000),
  8   partition idxp_n values less than(maxvalue));

Índice criado.

SQL> select index_name,
  2         partition_name,
  3         high_value,
  4         tablespace_name
  5    from user_ind_partitions;

INDEX_NAME         PARTITION_NAME           HIGH_VALUE TABLESPACE_NAME
------------------ ------------------------ ----------- -----------------------
IDX_T1_GLOBAL      IDXP_1500                1500       USERS
IDX_T1_GLOBAL      IDXP_2900                2900       USERS
IDX_T1_GLOBAL      IDXP_4600                4600       USERS
IDX_T1_GLOBAL      IDXP_5000                5000       USERS
IDX_T1_GLOBAL      IDXP_N                   MAXVALUE   USERS


A partir do Oracle 10g podemos também criar índices globais particionados por HASH como demonstrado abaixo:

SQL> create index idx_t1_global_hash on t1 (id)
  2  tablespace users
  3  global partition by hash (id)
  4  (partition idxp1,
  5   partition idxp2,
  6   partition idxp3,
  7   partition idxp4,
  8   partition idxp5);

Índice criado.

SQL> select index_name,
  2         partition_name,
  3         high_value,
  4         tablespace_name
  5    from user_ind_partitions;

INDEX_NAME         PARTITION_NAME           HIGH_VALUE TABLESPACE_NAME
------------------ ------------------------ ---------- ------------------------
IDX_T1_GLOBAL_HASH IDXP1                               USERS
IDX_T1_GLOBAL_HASH IDXP2                               USERS
IDX_T1_GLOBAL_HASH IDXP3                               USERS
IDX_T1_GLOBAL_HASH IDXP4                               USERS
IDX_T1_GLOBAL_HASH IDXP5                               USERS


Podemos notar que os índices globais não particionados são exatamente iguais aos índices regulares criados em uma tabela não particionada e, portanto, a sintaxe para a criação do índice é a mesma. A figura abaixo mostra o relacionamento entre um índice global não particionado e uma tabela particionada:


Por fim, vale a pena salientar que podemos criar também índices de bitmap em tabelas particionadas. A única restrição é que os mesmos só podem ser índice locais.

domingo, 6 de novembro de 2011

Desvendando o erro ORA-00955 durante a criação de uma primary key ou unique key

Olá,

É possível que muitos desenvolvedores já tenham passado pelo erro "ORA-00955: nome já está sendo usado por um objeto existente" durante a criação da primary key ou de uma unique key em uma tabela. Mas, porque isso acontece? Bom, sabemos que toda constraint (primary key ou unique key) ao ser criada, geralmente vem acompanhada também de um índice único criada com o mesmo nome da constraint. Mas, se por acaso algum índice já existente, seja ele único ou não, for útil à constraint, então o mesmo será utilizado por ela. Neste ponto, podemos chegar a conclusão de que o índice em si não é utilizado para garantir unicidade como muitos imaginam. Podemos verificar essa afirmação vendo o exemplo abaixo:
SQL> create table tabela1 (cod number);

Tabela criada.

-- criando um índice normal (não único)
SQL> create index idx_tabela1_cod on tabela1(cod);

Índice criado.

-- criando a chave primária
SQL> alter table tabela1 add constraint pk_tabela1 primary key (cod);

Tabela alterada.

SQL> select table_name,constraint_name,index_name from user_constraints;

TABLE_NAME CONSTRAINT_NAME INDEX_NAME
---------------------- ------------------------ ---------------------
TABELA1 PK_TABELA1 IDX_TABELA1_COD

Podemos ver pelo resultado acima que o Oracle não criou um índice chamado PK_TABELA1, em vez disso ele utilizou o índice IDX_TABELA1_COD existente. Tudo bem, mas o que aconteceria se dropássemos a chave primária? O índice seria dropado também?

A regra é, se o índice foi criado implicitamente durante a criação da constraint, então por padrão o Oracle irá dropar também o índice, a não ser que utilizemos a palavra chave (keep index) para manter o índice ao dropar a constraint.

Mas, e quanto em relação ao índice que já existia antes da criação da constraint? Neste caso, até a versão do Oracle 9i, o índice seria dropado também, pois por padrão, no Oracle 9i a cláusula (drop index) está implicitamente atrelada ao comando que dropa a constraint. Vejamos na demonstração abaixo:
SQL> select * from v$version;

BANNER
----------------------------------------------------------------
Oracle9i Enterprise Edition Release 9.2.0.4.0 - 64bit Production
PL/SQL Release 9.2.0.4.0 - Production
CORE 9.2.0.3.0 Production
TNS for Linux: Version 9.2.0.4.0 - Production
NLSRTL Version 9.2.0.4.0 - Production

SQL> create table t1 (id number);

Tabela criada.

SQL> create unique index pk_t1 on t1 (id);

Índice criado.

SQL> alter table t1 add constraint pk_t1 primary key (id);

Tabela alterada.

SQL> alter table t1 drop constraint pk_t1;

Tabela alterada.

SQL> select constraint_name from user_constraints where table_name='T1';

não há linhas selecionadas

SQL> select index_name from user_indexes where table_name='T1';

não há linhas selecionadas

Percebemos que, após droparmos a chave primária da tabela T1 no Oracle 9i, o índice que ela utilizava também foi dropado. O comando que o Oracle interpretou foi "alter table t1 drop constraint pk_t1 DROP INDEX" Por um lado, isso não é bom, pois não foi a PK quem criou o índice. O índice foi criado para ser utilizado para outros fins (performance, etc...) e o Oracle simplesmente dropa o índice sem nos avisar? Deve ser por esse motivo que o padrão mudou à partir do Oracle 10g:
SQL> select * from v$version;

BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - 64bi
PL/SQL Release 10.2.0.1.0 - Production
CORE 10.2.0.1.0 Production
TNS for Linux: Version 10.2.0.1.0 - Production
NLSRTL Version 10.2.0.1.0 - Production

SQL> create table t1 (id number);

Tabela criada.

SQL> create unique index pk_t1 on t1 (id);

Índice criado.

SQL> alter table t1 add constraint pk_t1 primary key (id);

Tabela alterada.

SQL> alter table t1 drop constraint pk_t1;

Tabela alterada.

SQL> select constraint_name from user_constraints where table_name='T1';

não há linhas selecionadas

SQL> select index_name from user_indexes where table_name='T1';

INDEX_NAME
--------------------
PK_T1

Podemos ver acima que, após droparmos a chave primária da tabela T1 no Oracle 10g R2, o índice que ela utilizava foi mantido. O comando que o Oracle 10g interpretou foi "alter table t1 drop constraint pk_t1 KEEP INDEX". Se quiséssemos dropar também o índice, teríamos que utilizar a cláusula (drop index). Vale a pena salientar que esse comportamento só é válido quando a constraint reutiliza um índice existente. Portanto, um índice que foi criado implicitamente durante a criação de uma constraint, também será dropado junto com a constraint.

Após essa longa introdução, irei demonstrar abaixo que uma simples exportação e importação de tabelas, seja via os utilitários exp/imp ou expdp/impdp, poderá ser a causa do erro ORA-00955 durante a criação de uma primary key ou unique key.

Vamos partir do comando abaixo:
SQL> create table t1 (id number constraint pk_t1 primary key);

Tabela criada.

Bom, já sabemos que se droparmos a chave primária da tabela T1, o índice que foi implicitamente criado também será dropado. Mas, o que acontece se exportamos essa tabela e a importarmos novamente no banco de dados? Para realização dos testes irei utilizar o Oracle 11g R2.

C:\>exp scott/tiger file=t1.dmp tables=t1

Export: Release 11.2.0.1.0 - Production on Dom Nov 6 10:01:39 2011

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

Conectado a: Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
Exportação executada no conjunto de caracteres de WE8MSWIN1252 e no conjunto de
caracteres de AL16UTF16 NCHAR

Sobre exportar tabelas especificadas ... via Caminho Convencional ...
. . exportando tabela T1 0 linhas exportadas
Exportação encerrada com sucesso, sem advertências.

Após a exportação da tabela T1 pelo utilitário (exp), irei verificar abaixo como o Oracle irá executar os comandos DDL de criação da tabela durante a importação:

C:\>imp scott/tiger file=t1.dmp indexfile=t1.txt

Import: Release 11.2.0.1.0 - Production on Dom Nov 6 10:03:14 2011

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

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

Arquivo de exportação criado por EXPORT:V11.02.00 via caminho convencional
importação realizada nos conjuntos de caracteres WE8MSWIN1252 e NCHAR AL16UTF16
. . ignorando tabela "T1"

Importação encerrada com sucesso, sem advertências.

C:\>type t1.txt

REM CREATE TABLE "SCOTT"."T1" ("ID" NUMBER) PCTFREE 10 PCTUSED 40
REM INITRANS 1 MAXTRANS 255 STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS
REM 1 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT) TABLESPACE
REM "USERS" LOGGING NOCOMPRESS ;
REM ... 0 rows
CONNECT SCOTT;
CREATE UNIQUE INDEX "SCOTT"."PK_T1" ON "T1" ("ID" ) PCTFREE 10 INITRANS 2
MAXTRANS 255 STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 FREELISTS 1
FREELIST GROUPS 1 BUFFER_POOL DEFAULT) TABLESPACE "USERS" LOGGING ;
REM ALTER TABLE "SCOTT"."T1" ADD CONSTRAINT "PK_T1" PRIMARY KEY ("ID")
REM USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE(INITIAL 65536
REM NEXT 1048576 MINEXTENTS 1 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL
REM DEFAULT) TABLESPACE "USERS" LOGGING ENABLE ;

Acima, podemos perceber que o Oracle irá primeiro criar o índice para depois criar a constraint primary key. Esse comportamento também é visto se utilizarmos o utilitário de exportação e importação Oracle DataPump:

C:\>expdp scott/tiger tables=t1 directory=data_pump_dir dumpfile=t1.dmp

Export: Release 11.2.0.1.0 - Production on Dom Nov 6 10:08:57 2011

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

Conectado a: Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
Iniciando "SCOTT"."SYS_EXPORT_TABLE_01": scott/******** tables=t1
directory=data_pump_dir dumpfile=t1.dmp
Estimativa em andamento com o método BLOCKS...
Processando o tipo de objeto TABLE_EXPORT/TABLE/TABLE_DATA
Estimativa total usando o método de BLOCKS: 0 KB
Processando o tipo de objeto TABLE_EXPORT/TABLE/TABLE
Processando o tipo de objeto TABLE_EXPORT/TABLE/INDEX/INDEX
Processando o tipo de objeto TABLE_EXPORT/TABLE/CONSTRAINT/CONSTRAINT
. . exportou "SCOTT"."T1" 0 KB 0 linhas
Tabela-mestre "SCOTT"."SYS_EXPORT_TABLE_01" carregada/descarregada com sucesso
******************************************************************************
Conjunto de arquivos de dump para SCOTT.SYS_EXPORT_TABLE_01 é:
E:\ORACLE\ADMIN\BD02\DPDUMP\T1.DMP
O job "SCOTT"."SYS_EXPORT_TABLE_01" foi concluído com sucesso em 10:09:27

Após a exportação da tabela T1 pelo utilitário (expdp), irei verificar abaixo como o Oracle irá executar os comandos DDL de criação da tabela durante a importação:

C:\>impdp scott/tiger tables=t1 directory=data_pump_dir dumpfile=t1.dmp sqlfile=t1.txt

Import: Release 11.2.0.1.0 - Production on Dom Nov 6 10:12:35 2011

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

Conectado a: Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
Tabela-mestre "SCOTT"."SYS_SQL_FILE_TABLE_01" carregada/descarregada com sucesso
Iniciando "SCOTT"."SYS_SQL_FILE_TABLE_01": scott/******** tables=t1
directory=data_pump_dir dumpfile=t1.dmp SQLFILE=t1.txt
Processando o tipo de objeto TABLE_EXPORT/TABLE/TABLE
Processando o tipo de objeto TABLE_EXPORT/TABLE/INDEX/INDEX
Processando o tipo de objeto TABLE_EXPORT/TABLE/CONSTRAINT/CONSTRAINT
O job "SCOTT"."SYS_SQL_FILE_TABLE_01" foi concluído com sucesso em 22:12:43

C:\>type E:\oracle\admin\BD02\dpdump\t1.txt

-- CONNECT SCOTT
ALTER SESSION SET EVENTS '10150 TRACE NAME CONTEXT FOREVER, LEVEL 1';
ALTER SESSION SET EVENTS '10904 TRACE NAME CONTEXT FOREVER, LEVEL 1';
ALTER SESSION SET EVENTS '25475 TRACE NAME CONTEXT FOREVER, LEVEL 1';
ALTER SESSION SET EVENTS '10407 TRACE NAME CONTEXT FOREVER, LEVEL 1';
ALTER SESSION SET EVENTS '10851 TRACE NAME CONTEXT FOREVER, LEVEL 1';
ALTER SESSION SET EVENTS '22830 TRACE NAME CONTEXT FOREVER, LEVEL 192 ';
-- new object type path: TABLE_EXPORT/TABLE/TABLE
CREATE TABLE "SCOTT"."T1"
( "ID" NUMBER
) SEGMENT CREATION IMMEDIATE
PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE
DEFAULT CELL_FLASH_CACHE DEFAULT)
TABLESPACE "USERS" ;

-- new object type path: TABLE_EXPORT/TABLE/INDEX/INDEX
CREATE UNIQUE INDEX "SCOTT"."PK_T1" ON "SCOTT"."T1" ("ID")
PCTFREE 10 INITRANS 2 MAXTRANS 255
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE
DEFAULT CELL_FLASH_CACHE DEFAULT)
TABLESPACE "USERS" PARALLEL 1 ;

ALTER INDEX "SCOTT"."PK_T1" NOPARALLEL;

-- new object type path: TABLE_EXPORT/TABLE/CONSTRAINT/CONSTRAINT
ALTER TABLE "SCOTT"."T1" ADD CONSTRAINT "PK_T1" PRIMARY KEY ("ID")
USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE
DEFAULT CELL_FLASH_CACHE DEFAULT)
TABLESPACE "USERS" ENABLE;

Da mesma forma como aconteceu no exemplo com os utilitários (exp/imp), podemos perceber acima que o Oracle também irá primeiro criar o índice para depois criar a constraint primary key. Após a importação da tabela T1, irei simular abaixo o erro ORA-00955:
C:\>sqlplus scott/tiger

SQL*Plus: Release 11.2.0.1.0 Production on Dom Nov 6 10:23:45 2011

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

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

SQL> alter table t1 drop primary key;

Tabela alterada.

SQL> alter table t1 add (id2 number);

Tabela alterada.

SQL> alter table t1 add constraint pk_t1 primary key (id,id2);
alter table t1 add constraint pk_t1 primary key (id,id2)
* ERRO na linha 1: ORA-00955: nome já está sendo usado por um objeto existente

Perceberam o motivo do erro? O Oracle tentou criar um índice com o nome PK_T1. A questão é que o índice que foi utilizado pela chave primária anterior foi mantido no banco de dados:
SQL> select table_name,index_name from user_indexes;

TABLE_NAME INDEX_NAME
------------------------------ ------------------------------
T1 PK_T1

A explicação é que, após dropar a chave primária, criar uma nova coluna na tabela e criar novamente a chave primária, o índice PK_T1 existente não foi reaproveitado (por motivos óbvios). Neste caso, o Oracle tentou criar um índice com o mesmo nome da constraint, o que gerou o erro ORA-00955. Para resolver o problema teremos que dropar o índice PK_T1 explicitamente antes de criar a nova primary key.
SQL> drop index pk_t1;

Índice eliminado.

SQL> alter table t1 add constraint pk_t1 primary key (id,id2);

Tabela alterada.

terça-feira, 4 de outubro de 2011

Criando um banco de dados no modo silencioso com o DBCA

Olá,
Para aqueles que já conhecem a interface gráfica do assistente de configuração de banco de dados do Oracle, sabem que estou falando do DBCA (Database Configuration Assistant). No Oracle 10g, por exemplo, o DBCA fornece 4 tipos de templates (gabaritos), para que o DBA possa escolher aquele mais adequado ao tipo de banco a ser criado.


Na figura acima existe um template adicional, criado por mim que será utilizado mais a frente. Até então, o Oracle fornece quatro modelos: Finalidade geral, processamento de transações, Data Warehouse e banco de dados personalizado. Exceto para banco de dados personalizado, os outros três são templates do tipo seed (que incluem arquivos de dados). A vantagem dos templates do tipo seed é que os mesmos poupam tempo na criação de banco de dados, porque a cópia dos arquivos de banco de dados já criados para os locais corretos, leva menos tempo do que criá-los do zero. Os templates são armazenados no diretório $ORACLE_HOME/assistants/dbca/templates e tem um formato do tipo XML. Uma outra vantagem dos templates é que os mesmos são fáceis de compartilhar e podem ser copiados de uma máquina para outra.

Existem dois tipos de templates: seeds e nonseeds. O templates do tipo seed têm a extensão (*.dbc) e incluem os arquivos de dados de um banco de dados, em um arquivo especial com a extensão (*.dfb). Ao criar um banco de dados usando o DBCA, se você escolher algum modelo do tipo seed, a criação de banco de dados será mais rápida porque os arquivos físicos do banco de dados já foram criados. Portanto, a criação do banco de dados começa como uma cópia do banco de dados do seed, em vez de ter que ser criado. Na verdade, o DBCA copia os arquivos de dados para o local especificado, cria um arquivo de controle e abre o banco de dados com a opção RESETLOGS. Já um template do tipo nonseed tem a extensão (*.dbt) e não inclui qualquer arquivo de banco de dados. Se você escolher um modelo nonseed ao criar o banco de dados, o assistente irá criar um novo banco de dados e executar todos os scripts necessários, como os scripts catalog.sql e catproc.sql, por exemplo.

No mais, irei utilizar abaixo um template do tipo nonseed criado por mim, e o utilizarei para criar um banco de dados sem a necessidade de utilizar a interface gráfica do DBCA (silent mode). Eu criei um template e o chamei de templatepadrao10g.dbt, conforme demonstrado pelo código abaixo:

<DatabaseTemplate name="padrao" description="Template padrao 10g" version="10.2.0.0.0">
<CommonAttributes>
<option name="ISEARCH" value="false"/>
<option name="OMS" value="false"/>
<option name="JSERVER" value="false"/>
<option name="SPATIAL" value="false"/>
<option name="ODM" value="false">
<tablespace id="SYSAUX"/>
</option>
<option name="IMEDIA" value="false"/>
<option name="XDB_PROTOCOLS" value="false">
<tablespace id="SYSAUX"/>
</option>
<option name="ORACLE_TEXT" value="false">
<tablespace id="SYSAUX"/>
</option>
<option name="SAMPLE_SCHEMA" value="false"/>
<option name="CWMLITE" value="false">
<tablespace id="SYSAUX"/>
</option>
<option name="EM_REPOSITORY" value="false">
<tablespace id="SYSAUX"/>
</option>
<option name="HTMLDB" value="false"/>
<option name="NET_EXTENSIONS" value="false"/>
</CommonAttributes>
<Variables/>
<CustomScripts Execute="false"/>
<InitParamAttributes>
<InitParams>
<initParam name="pga_aggregate_target" value="60" unit="MB"/>
<initParam name="nls_territory" value="BRAZIL"/>
<initParam name="processes" value="150"/>
<initParam name="db_recovery_file_dest_size" value="2048" unit="MB"/>
<initParam name="nls_language" value="BRAZILIAN PORTUGUESE"/>
<initParam name="control_files" value="(&quot;{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\control01.ctl&quot;, &quot;{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\control02.ctl&quot;, &quot;{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\control03.ctl&quot;)"/>
<initParam name="sga_target" value="200" unit="MB"/>
<initParam name="compatible" value="10.2.0.1.0"/>
<initParam name="background_dump_dest" value="{ORACLE_BASE}\admin\{DB_UNIQUE_NAME}\bdump"/>
<initParam name="job_queue_processes" value="10"/>
<initParam name="user_dump_dest" value="{ORACLE_BASE}\admin\{DB_UNIQUE_NAME}\udump"/>
<initParam name="audit_file_dest" value="{ORACLE_BASE}\admin\{DB_UNIQUE_NAME}\adump"/>
<initParam name="db_domain" value=""/>
<initParam name="open_cursors" value="300"/>
<initParam name="db_block_size" value="8" unit="KB"/>
<initParam name="db_recovery_file_dest" value="{ORACLE_BASE}\flash_recovery_area"/>
<initParam name="undo_tablespace" value="UNDOTBS1"/>
<initParam name="core_dump_dest" value="{ORACLE_BASE}\admin\{DB_UNIQUE_NAME}\cdump"/>
<initParam name="remote_login_passwordfile" value="EXCLUSIVE"/>
<initParam name="undo_management" value="AUTO"/>
<initParam name="db_file_multiblock_read_count" value="16"/>
</InitParams>
<MiscParams>
<customSGA>true</customSGA>
<archiveLogMode>false</archiveLogMode>
<initParamFileName>{ORACLE_BASE}\admin\{DB_UNIQUE_NAME}\pfile\init.ora</initParamFileName>
</MiscParams>
<SPfile useSPFile="true">{ORACLE_HOME}\database\spfile{SID}.ora</SPfile>
</InitParamAttributes>
<StorageAttributes>
<ControlfileAttributes id="Arquivo de controle">
<maxDatafiles>100</maxDatafiles>
<maxLogfiles>16</maxLogfiles>
<maxLogMembers>3</maxLogMembers>
<maxLogHistory>1</maxLogHistory>
<maxInstances>8</maxInstances>
<image name="control01.ctl" filepath="{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\"/>
<image name="control02.ctl" filepath="{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\"/>
<image name="control03.ctl" filepath="{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\"/>
</ControlfileAttributes>
<DatafileAttributes id="{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\sysaux01.dbf">
<tablespace>SYSAUX</tablespace>
<temporary>false</temporary>
<online>true</online>
<status>0</status>
<size unit="MB">120</size>
<reuse>true</reuse>
<autoExtend>true</autoExtend>
<increment unit="KB">10240</increment>
<maxSize unit="MB">-1</maxSize>
</DatafileAttributes>
<DatafileAttributes id="{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\system01.dbf">
<tablespace>SYSTEM</tablespace>
<temporary>false</temporary>
<online>true</online>
<status>0</status>
<size unit="MB">300</size>
<reuse>true</reuse>
<autoExtend>true</autoExtend>
<increment unit="KB">10240</increment>
<maxSize unit="MB">-1</maxSize>
</DatafileAttributes>
<DatafileAttributes id="{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\temp01.dbf">
<tablespace>TEMP</tablespace>
<temporary>false</temporary>
<online>true</online>
<status>0</status>
<size unit="MB">20</size>
<reuse>true</reuse>
<autoExtend>true</autoExtend>
<increment unit="KB">640</increment>
<maxSize unit="MB">-1</maxSize>
</DatafileAttributes>
<DatafileAttributes id="{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\undotbs01.dbf">
<tablespace>UNDOTBS1</tablespace>
<temporary>false</temporary>
<online>true</online>
<status>0</status>
<size unit="MB">200</size>
<reuse>true</reuse>
<autoExtend>true</autoExtend>
<increment unit="KB">5120</increment>
<maxSize unit="MB">-1</maxSize>
</DatafileAttributes>
<DatafileAttributes id="{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\users01.dbf">
<tablespace>USERS</tablespace>
<temporary>false</temporary>
<online>true</online>
<status>0</status>
<size unit="MB">5</size>
<reuse>true</reuse>
<autoExtend>true</autoExtend>
<increment unit="KB">1280</increment>
<maxSize unit="MB">-1</maxSize>
</DatafileAttributes>
<TablespaceAttributes id="SYSAUX">
<online>true</online>
<offlineMode>1</offlineMode>
<readOnly>false</readOnly>
<temporary>false</temporary>
<defaultTemp>false</defaultTemp>
<undo>false</undo>
<local>true</local>
<blockSize>-1</blockSize>
<allocation>1</allocation>
<uniAllocSize unit="KB">-1</uniAllocSize>
<initSize unit="KB">64</initSize>
<increment unit="KB">64</increment>
<incrementPercent>50</incrementPercent>
<minExtends>1</minExtends>
<maxExtends>4096</maxExtends>
<minExtendsSize unit="KB">64</minExtendsSize>
<logging>true</logging>
<recoverable>false</recoverable>
<maxFreeSpace>0</maxFreeSpace>
<autoSegmentMgmt>true</autoSegmentMgmt>
<bigfile>false</bigfile>
<datafilesList>
<TablespaceDatafileAttributes id="{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\sysaux01.dbf">
<id>-1</id>
</TablespaceDatafileAttributes>
</datafilesList>
</TablespaceAttributes>
<TablespaceAttributes id="SYSTEM">
<online>true</online>
<offlineMode>1</offlineMode>
<readOnly>false</readOnly>
<temporary>false</temporary>
<defaultTemp>false</defaultTemp>
<undo>false</undo>
<local>true</local>
<blockSize>-1</blockSize>
<allocation>3</allocation>
<uniAllocSize unit="KB">-1</uniAllocSize>
<initSize unit="KB">64</initSize>
<increment unit="KB">64</increment>
<incrementPercent>50</incrementPercent>
<minExtends>1</minExtends>
<maxExtends>-1</maxExtends>
<minExtendsSize unit="KB">64</minExtendsSize>
<logging>true</logging>
<recoverable>false</recoverable>
<maxFreeSpace>0</maxFreeSpace>
<autoSegmentMgmt>true</autoSegmentMgmt>
<bigfile>false</bigfile>
<datafilesList>
<TablespaceDatafileAttributes id="{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\system01.dbf">
<id>-1</id>
</TablespaceDatafileAttributes>
</datafilesList>
</TablespaceAttributes>
<TablespaceAttributes id="TEMP">
<online>true</online>
<offlineMode>1</offlineMode>
<readOnly>false</readOnly>
<temporary>true</temporary>
<defaultTemp>true</defaultTemp>
<undo>false</undo>
<local>true</local>
<blockSize>-1</blockSize>
<allocation>1</allocation>
<uniAllocSize unit="KB">-1</uniAllocSize>
<initSize unit="KB">64</initSize>
<increment unit="KB">64</increment>
<incrementPercent>0</incrementPercent>
<minExtends>1</minExtends>
<maxExtends>0</maxExtends>
<minExtendsSize unit="KB">64</minExtendsSize>
<logging>true</logging>
<recoverable>false</recoverable>
<maxFreeSpace>0</maxFreeSpace>
<autoSegmentMgmt>true</autoSegmentMgmt>
<bigfile>false</bigfile>
<datafilesList>
<TablespaceDatafileAttributes id="{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\temp01.dbf">
<id>-1</id>
</TablespaceDatafileAttributes>
</datafilesList>
</TablespaceAttributes>
<TablespaceAttributes id="UNDOTBS1">
<online>true</online>
<offlineMode>1</offlineMode>
<readOnly>false</readOnly>
<temporary>false</temporary>
<defaultTemp>false</defaultTemp>
<undo>true</undo>
<local>true</local>
<blockSize>-1</blockSize>
<allocation>1</allocation>
<uniAllocSize unit="KB">-1</uniAllocSize>
<initSize unit="KB">512</initSize>
<increment unit="KB">512</increment>
<incrementPercent>50</incrementPercent>
<minExtends>8</minExtends>
<maxExtends>4096</maxExtends>
<minExtendsSize unit="KB">512</minExtendsSize>
<logging>true</logging>
<recoverable>false</recoverable>
<maxFreeSpace>0</maxFreeSpace>
<autoSegmentMgmt>true</autoSegmentMgmt>
<bigfile>false</bigfile>
<datafilesList>
<TablespaceDatafileAttributes id="{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\undotbs01.dbf">
<id>-1</id>
</TablespaceDatafileAttributes>
</datafilesList>
</TablespaceAttributes>
<TablespaceAttributes id="USERS">
<online>true</online>
<offlineMode>1</offlineMode>
<readOnly>false</readOnly>
<temporary>false</temporary>
<defaultTemp>false</defaultTemp>
<undo>false</undo>
<local>true</local>
<blockSize>-1</blockSize>
<allocation>1</allocation>
<uniAllocSize unit="KB">-1</uniAllocSize>
<initSize unit="KB">128</initSize>
<increment unit="KB">128</increment>
<incrementPercent>0</incrementPercent>
<minExtends>1</minExtends>
<maxExtends>4096</maxExtends>
<minExtendsSize unit="KB">128</minExtendsSize>
<logging>true</logging>
<recoverable>false</recoverable>
<maxFreeSpace>0</maxFreeSpace>
<autoSegmentMgmt>true</autoSegmentMgmt>
<bigfile>false</bigfile>
<datafilesList>
<TablespaceDatafileAttributes id="{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\users01.dbf">
<id>-1</id>
</TablespaceDatafileAttributes>
</datafilesList>
</TablespaceAttributes>
<RedoLogGroupAttributes id="1">
<reuse>false</reuse>
<fileSize unit="KB">51200</fileSize>
<Thread>1</Thread>
<member ordinal="0" memberName="redo01.log" filepath="{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\"/>
</RedoLogGroupAttributes>
<RedoLogGroupAttributes id="2">
<reuse>false</reuse>
<fileSize unit="KB">51200</fileSize>
<Thread>1</Thread>
<member ordinal="0" memberName="redo02.log" filepath="{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\"/>
</RedoLogGroupAttributes>
<RedoLogGroupAttributes id="3">
<reuse>false</reuse>
<fileSize unit="KB">51200</fileSize>
<Thread>1</Thread>
<member ordinal="0" memberName="redo03.log" filepath="{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\"/>
</RedoLogGroupAttributes>
</StorageAttributes>
</DatabaseTemplate>


Agora iniciarei a criação de um banco de dados no modo silent que chamarei de BD03. Preste atenção nos parâmetros que eu passo para o DBCA.

C:\>dbca -silent -createDatabase
    -templateName templatepadrao10g.dbt
    -gdbName BD03 -sysPassword manager -systemPassword manager
    -characterset WE8ISO8859P1 -nationalCharacterSet AL16UTF16
    -emConfiguration NONE -databaseType OLTP

Criando e iniciando a instância Oracle
2% concluído
3% concluído
5% concluído
12% concluído
Criando arquivos de banco de dados
13% concluído
25% concluído
Criando views de dicionário de dados
28% concluído
32% concluído
36% concluído
37% concluído
38% concluído
39% concluído
40% concluído
41% concluído
42% concluído
43% concluído
44% concluído
45% concluído
52% concluído
56% concluído
60% concluído
61% concluído
64% concluído
Concluindo Criação de Banco de Dados
67% concluído
71% concluído
75% concluído
86% concluído
97% concluído
100% concluído

Pronto. Fácil e prático, não?

C:\>sqlplus / as sysdba

SQL*Plus: Release 10.2.0.1.0 - Production on Ter Out 4 21:10:01 2011

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

Conectado a:
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options

SQL> select name from v$database;

NAME
-------------
BD03

SQL> select instance_name from v$instance;

INSTANCE_NAME
-------------
bd03

SQL> select * from nls_database_parameters;

PARAMETER                      VALUE
------------------------------ -------------------------------
NLS_LANGUAGE                   BRAZILIAN PORTUGUESE
NLS_TERRITORY                  BRAZIL
NLS_CURRENCY                   R$
NLS_ISO_CURRENCY               BRAZIL
NLS_NUMERIC_CHARACTERS         ,.
NLS_CHARACTERSET               WE8ISO8859P1
NLS_CALENDAR                   GREGORIAN
NLS_DATE_FORMAT                DD/MM/RR
NLS_DATE_LANGUAGE              BRAZILIAN PORTUGUESE
NLS_SORT                       WEST_EUROPEAN
NLS_TIME_FORMAT                HH24:MI:SSXFF
NLS_TIMESTAMP_FORMAT           DD/MM/RR HH24:MI:SSXFF
NLS_TIME_TZ_FORMAT             HH24:MI:SSXFF TZR
NLS_TIMESTAMP_TZ_FORMAT        DD/MM/RR HH24:MI:SSXFF TZR
NLS_DUAL_CURRENCY              Cr$
NLS_COMP                       BINARY
NLS_LENGTH_SEMANTICS           BYTE
NLS_NCHAR_CONV_EXCP            FALSE
NLS_NCHAR_CHARACTERSET         AL16UTF16
NLS_RDBMS_VERSION              10.2.0.1.0

20 linhas selecionadas.

Bom, da mesma forma que podemos criar, podemos também dropar um banco de dados com o DBCA. Antes disso, no exemplo abaixo irei aproveitar e demonstrar como dropar um banco de dados utilizando o comando DROP DATABASE emitido de dentro do SQL*Plus.

C:\>sqlplus / as sysdba

SQL*Plus: Release 10.2.0.1.0 - Production on Ter Out 4 21:30:01 2011

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

Conectado a:
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options

SQL> startup mount force restrict
Instância ORACLE iniciada.

Total System Global Area  209715200 bytes
Fixed Size                  1248140 bytes
Variable Size              71304308 bytes
Database Buffers          134217728 bytes
Redo Buffers                2945024 bytes
Banco de dados montado.

SQL> drop database;

Banco de Dados eliminado.

A outra forma seria utilizando o próprio DBCA como demonstrado abaixo:

C:\>dbca -silent -deleteDatabase 
    -sourceDB BD03 
    -sysDBAUserName SYS
    -sysDBAPassword manager

Estabelecendo conexão com o banco de dados
4% concluído
9% concluído
14% concluído
47% concluído
Atualizando arquivos de configuração de rede
48% concluído
52% concluído
Deletando instância e arquivos de dados
76% concluído
100% concluído

domingo, 4 de setembro de 2011

Um pouco sobre o Flashback Database 10g/11g ...

Olá,

Para quem já teve a oportunidade de utilizar esta feature disponível desde a versão do Oracle 10g deve percebido o quanto a mesma é incrível. Na minha visão a tecnologia flashback é uma das features mais incríveis e uma das que eu eu mais gosto no Oracle. Nessas últimas semanas tenho trabalhado muito em algumas bases de mais ou menos 1 TB de tamanho realizando flahback database em um ambiente montado para realização de cenários de teste repetidos. Aliás, prefiro criar pontos de restauração garantidos (Guaranted Restore Point) que é uma feature nova no Oracle 10g R2 para não ter que depender do parâmetro DB_FLASHBACK_RETENTION_TARGET (default 24 horas). Houve um dia que uma operação de flashback database demorou cerca de 4 horas para voltar uma base até um ponto específico no tempo dentro da janela flashback. Não foi surpresa pra mim pois nesse meio tempo tinham sido realizadas várias operações DML e DDL como criação de índices, particionamentos de tabelas entre outras operações em muitas tabelas gigantescas. Fico pensando quanto tempo demoraria se tivéssemos que voltar um backup!

Como eu disse anteriormente, o flashback database é muito útil nos casos em que temos vários cenários de testes repetidos. Digamos que você tem uma aplicação que está sendo testada em um ambiente de desenvolvimento. Toda vez que você executa a aplicação, ela executas vários comandos DML e, desta forma, altera vários registros em várias tabelas. Em um determinado momento ao final dos testes, você deseja retornar os dados para os seus valores originais antes da realização do próximo teste. Portanto, o flashback é uma ferramenta excelente para isso.

Bom, diferente de outras tecnologias flashback como a flashback query por exemplo, o flashback database não depende da retenção de blocos no tablespace de UNDO. Quando o flashback database está habilitado ou até mesmo quando não está, mas algum ponto de restauração garantido existe, o Oracle registra informações extras na Flash Recovery Area (no 11g o termo agora é Fast Recovery Area) em arquivos chamados de flashback logs. Os logs de flashback possuem os dados para retornar os blocos até um tempo anterior. O legal do flashback database é que podemos voltar o banco em um determinado tempo no passado e abrir o banco no modo read only para ver se voltou o suficiente. Caso contrário, poderemos avançar no tempo ou retroceder ainda mais quantas vezes forem necessárias antes de abrir o banco com a opção resetlogs. O interessante é que mesmo após abrir o banco com a opção resetlogs, ainda assim poderemos utilizar os pontos de restauração criados e ainda não removidos. A figura abaixo nos dá uma visão geral de algumas das possibilidades dentro de uma janela de tempo em que poderemos atuar:




Vale a pena salientar que pontos de restauração garantidos ficarão eternos até que sejam removidos. Por outro lado, caso um ponto de restauração garantido não seja criado e a Flash Recovery Area precisar de mais espaço para acomodar outros tipos de arquivos, os flashback logs que foram gerados serão removidos para dar espaço a outros tipos de arquivos, como archive logs e arquivos de backup do RMAN. Portanto, seja cuidadoso ao criar um ponto de restauração garantido pois os logs de flashback crescerão até que o mesmo seja removido. Um outro ponto importante a dizer é que para que o flashback seja ativado o banco de dados precisar estar em modo ARCHIVELOG, ou seja, em algum momento os archive logs gerados serão necessários para dar suporte aos flashback logs. Então, não apague nenhum archive log. Me lembro de algumas vezes ter tido que realizar o flashback de dentro do RMAN, pois alguns archive logs necessários para realização do flashback não estavam mais no disco e sim em algum backupset, devido a estratégia de política de backup em vigor.

No mais, neste artigo irei demonstrar como o flashback database reage às alterações de algumas propriedades dos tablespaces e datafiles (create, resize, drop) realizados dentro da janela flashback. Em alguns momentos tive que abrir mão de alguns datafiles no momento da realização do flashback database. Neste caso, é bom termos cuidado pois dependendo da alteração estrutural no nível de datafiles realizada no banco de dados, essa alteração poderá impactar no flashback da base de dados de forma total ou parcial.

Inicialmente irei realizar um teste no Oracle 10g R2 e depois irei realizar um teste no Oracle 11g R2 para demonstrar alguns pontos.



Acima estão listados os tablespaces e seus respectivos datafiles do meu banco de dados. Abaixo irei realizar um shutdown do banco para iniciá-lo em estado MOUNT afim de ativar o modo flashback.


O comando "archive log list" me mostra que o banco já está operando no modo ARCHIVELOG.


Acima verifiquei o destino e o tamanho da Flash Recovery Area. Deixarei de lado o parâmetro DB_FLASHBACK_RETENTION_TARGET na qual o valor default é 24 horas, pois irei criar pontos de restauração garantidos e neste caso este período de retenção será desconsiderado.


Após ativar o flashback database, irei criar a abaixo um ponto de restauração garantido com o nome de "stable".



Pronto. O banco já está com o suporte de flashback ativado e com um ponto de restauração criado. Abaixo irei realizar algumas operações como criar uma tablespace, renomear uma tablespaces, dropar outra, e redimensionar alguns datafiles.




Após realizadas as alterações acima, o layout do meu de banco de dados ficou como demonstrado pelo resultado da query acima. Agora irei realizar o flashback database para o restore point criado anteriormente. Para tanto, será necessário deixar a base no estado MOUNT.



Acima está uma lição a ser aprendida e que está muito bem documentada. Não efetue nenhuma operação de redução de tamanho de datafile enquanto o banco de dados estiver com o flashback ativo. Como demonstrado acima, o datafile 4 pertencente ao tablespace USERS inviabilizou a realização do flashback.



Colocar o datafile 4 em modo off-line não bastou para resolver o problema.



Portanto, terei de abrir mão do datafile 4 executando o comando abaixo.




Agora irei tentar realizar novamente o flashback do banco de dados.



Em relação ao datafile 4 o problema foi resolvido abrindo mão do mesmo, mas agora o Oracle está reclamando do datafile 5 que pertence ao tablespace TBS01 que foi dropado. Bom, uma outra lição aprendida é de que o flashback database não recupera tablespaces e datafiles que foram removidos.



Por fim, poderei realizar o flashback database com sucesso como demonstrado abaixo:



Conclusão:
  • A tablespace TBS03 que foi criada após o ponto de restauração foi removida do banco de dados.
  • O datafile 3 pertencente ao tablespace SYSAUX que teve o seu tamanho aumentado voltou para o seu tamanho original.
  • O datafile 4 pertencente ao tablespace USERS que teve o seu tamanho reduzido permanenceu off-line e portanto foi perdido. Qualquer tentativa de recover do mesmo precisará de um backup de uma incarnação anterior.
  • A tablespace TBS02 que foi renomeada para TABLESPACE02 foi desfeita e voltou para o nome original.
  • A tablespace TBS01 que foi dropada, não foi recuperada e portanto, o seu datafile foi perdido.

Nos testes que realizei com o Oracle 11g R2, verifiquei que o comando "alter database flashback on" pode ser emito também enquanto o banco de dados está aberto (OPEN) e não mais somente no estado MOUNT. Em relação a operação de redução do tamanho de um datafile, o mesmo inviabilizou o flashback do banco de dados, mas agora não será necessário utilizar a cláusula offline-drop do comando "alter database datafile" como demonstrado abaixo.


Em relação a criação de um ponto de restauração garantido sem o modo de flashback ativado, podemos verificar abaixo que o mesmo é possível nas versões 10g R2 e 11g como demonstrado abaixo:



Os valores possíveis para a coluna FLASHBACK_ON da view V$DATABASE da versão 10g R1 são (YES/NO). Na versão 10g R2 foi incluído o valor "RESTORE POINT ONLY" o que significa que só é possível realizar o flashback do banco de dados para um ponto de restauração.




Acima foi até possível pegar um erro de tradução para o português da mensagem do erro ORA-38726. O certo seria "ORA-38726: Log do banco de dados de flashback não está ativado."

No mais, após remover o ponto de restauração, poderemos perceber que o valor da coluna FLASHBACK_ON da view V$DATABASE terá o seu valor atualizado para "NO".