quinta-feira, 15 de dezembro de 2011

Índices Invisíveis no Oracle 11g


Neste artigo abordarei sobre índices invisíveis no Oracle 11g, importante dispositivo que permite testar e validar a utilização e necessidade de um índice num ambiente produtivo de banco de dados.

O Oracle 11g permite que os índices sejam marcados como invisíveis. Os índices invisíveis são mantidos como qualquer outro índice, mas eles são ignorados pelo otimizador, a menos que o parâmetro OPTIMIZER_USE_INVISIBLE_INDEXES esteja definido como TRUE. Os índices podem ser criados como invisíveis, usando a palavra-chave INVISIBLE, e sua visibilidade pode ser alterada usando o comando ALTER INDEX.

Exemplo de criação de um índice invisível:

CREATE INDEX ON () INVISIBLE;

Ativação/desativação de um índice:

ALTER INDEX INVISIBLE;
ALTER INDEX VISIBLE;

O script a abaixo cria e preenche uma tabela, em seguida, cria um índice invisível.

Criação da tabela “TEST_TAB”:

CREATE TABLE TEST_TAB(id  NUMBER);


Preenchimento de dados na tabela “TEST_TAB”.

BEGIN
  FOR i IN 1..1000 LOOP
    INSERT INTO TEST_TAB VALUES (i);
  END LOOP;
  COMMIT;
END;
/


Criação do índice invisível, “TEST_TAB_ID” para a tabela “TEST_TAB”.

CREATE INDEX TEST_TAB_ID ON TEST_TAB(id) INVISIBLE;


Atualização das estatísticas da tabela “TEST_TAB” e do índice “TEST_TAB_ID”.

EXEC DBMS_STATS.gather_table_stats(TEST, 'TEST_TAB', cascade=> TRUE);

Para demonstrar como um índice invisível funciona, vamos executar uma consulta usando a coluna indexada, definida na cláusula WHERE.

SET AUTOTRACE ON

SELECT * FROM test_tab WHERE id = 999;

------------------------------------------------------------------------------
| Id  | Operation         | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------==--------------------------------------
|   0 | SELECT STATEMENT  |          |     1 |     3 |     7   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| TEST_TAB |     1 |     3 |     7   (0)| 00:00:01 |
------------------------------------------------------------------------------

Pode-se verificar que o índice foi ignorado, pois a operação de “TABLE ACCESS FULL” é apresentada no plano de execução da consulta, essa operação realiza a varredura completa da tabela desprezando o índice da tabela.

Ao definir o parâmetro OPTIMIZER_USE_INVISIBLE_INDEXES como TRUE e ativando a “visibilidade” do índice, o otimizador utiliza o índice durante a execução da consulta, conforme demonstrado abaixo.

ALTER SESSION SET OPTIMIZER_USE_INVISIBLE_INDEXES=TRUE;

SELECT * FROM test_tab WHERE id = 999;

--------------------------------------------------------------------------------
| Id  | Operation        | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT |             |     1 |     3 |     1   (0)| 00:00:01 |
|*  1 |  INDEX RANGE SCAN| TEST_TAB_ID |     1 |     3 |     1   (0)| 00:00:01 |
--------------------------------------------------------------------------------

Porém, ao tornar o índice visível, mas com o parâmetro OPTIMIZER_USE_INVISIBLE_INDEXES definido como FALSE, essa instrução ainda indicará ao otimizador que o índice ainda disponível para uso.

ALTER SESSION SET OPTIMIZER_USE_INVISIBLE_INDEXES=FALSE;

ALTER INDEX test_tab_id VISIBLE;

SELECT * FROM test_tab WHERE id = 9999;

--------------------------------------------------------------------------------
| Id  | Operation        | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT |             |     1 |     3 |     1   (0)| 00:00:01 |
|*  1 |  INDEX RANGE SCAN| TEST_TAB_ID |     1 |     3 |     1   (0)| 00:00:01 |
--------------------------------------------------------------------------------

Para resolver esse impasse deve-se modificar o índice para INVISIBLE.

Índices invisíveis podem ser uteis para processos com necessidades específicas de indexação, onde a presença dos índices pode afetar negativamente outras áreas funcionais. Eles também são úteis para testar o impacto de descartar um índice.

A visibilidade dos índices pode ser implementada configurando o parâmetro OPTIMIZER_USE_INVISIBLE_INDEXES como TRUE, para todo o banco de dados através da configuração do arquivo “spfile” ou do “init.ora” ou ainda pode ser implementado através da sessão de um usuário. A ativação ou desativação desse parâmetro é dinâmica.

Para verificar os estados de visibilidade de um índice deve-se verificar a coluna “VISIBILITY” das visões [DBA | ALL | USER] _INDEXES.



Rubens Oliveira
DBA Oracle Consultor
olivert.dba@consultant.com

segunda-feira, 5 de dezembro de 2011

Oracle Standby Database 2/2


Na segunda parte do artigo sobre Oracle Standby, descreverei os procedimentos para o gerenciamento do banco de dados.

Seguem abaixo os passos necessários para o gerenciamento de um “Standby Database”.


PARA A VERIFICAÇÃO DO STANDBY

1.   Conectar-se na base de dados primário (origem) para gerar novos “archives”.
Executar:  alter system archive log current;
alter system switch logfile;
   archive log list;

2.   Para verificar a atualização do “standby”

Executar: select sequence#, first_time, next_time
                        from v$archived_log order by sequence#;

3.   Para verificar os processos e status do “standby”

Executar: select process, status from v$managed_standby; 

4.   Para a verificação automática executar foi criado um script shell [verify_sync_stb.sh], fonte disponível no final do artigo.

5.   Para a remoção dos  “archives logs” já aplicados foi criado um script shell [clear_archives.sh], fonte disponível no final do artigo.


PARA A ATIVAÇÃO DO STANDBY EM MODO READ-ONLY

1.   Verificar se o banco de dados “standby” está no ar.
Caso esteja deve-se baixá-lo utilizando o comando abaixo:
Executar: shutdown immediate;

2.   Na seqüência, levantar o banco de dados “standby”
Executar:  startup nomount;
alter database mount standby database;
alter database open read only;

3.   Para verificar o status do “standby” executar a consulta abaixo:
Executar: select name,created,log_mode,database_role from v$database;



PARA A ATIVAÇÃO DO STANDBY EM MODO READ-WRITE

1.   Verificar as atualizações do banco de dados e ver se todos os “archives” pendentes foram aplicados.
Executar: select thread#, sequence#, first_change#, next_change# from v$log_history;

2.   Na sequência baixar o “standby” utilizando o comando abaixo:
Executar: shutdown immediate;

3.   Levantar o banco de dados “standby” usando os comandos abaixo:
Executar:  startup nomount;
alter database mount standby database;
recover standby database until cancel;
alter database activate standby database;
shutdown immediate;


4.   Levantar o “standby” :
Executar : startup;

Atenção:  A partir desse momento o banco de dados deixará de ser STANDBY e torna-se o banco de dados PRIMÁRIO.

5.   Realizar a validação do status do banco de dados
Executar: select name,created,log_mode,database_role from v$database;

6.   Levantar o serviço de listener.
Executar: lsnrctl start

Deve-re realizar um re-apontamento do arquivo TNSNAMES.ora na rede para que as aplicações possam conectar-se ao novo banco de dados primário.




Script - verify_sync_stb.sh

Script que realiza a verificação do sincronismo do standby, ao término, é enviado – via e-mail, um log contendo o tempo de início e fim do processo e também os processos de “recover” no “standby”.

Abaixo segue o código fonte:


. $HOME/.profile

export ORACLE_SID=basestd
export ORACLE_HOME=/u01/app/oracle/ora11g

ARQLOG=/home/oracle/verify_arch_updt.log

sqlplus sys/@base    as sysdba @$HOME/checksync.sql
sqlplus sys/@basestd as sysdba @$HOME/getsync.sql

cat $HOME/sync.txt > $ARQLOG

# Envia email informando status da execucao
#
MAIL_SUB="VERIFICACAO DO SINCRONISMO DO STANDBY: BASESTD"
MAIL_FILE=/home/oracle/logs/verf_mail.txt
mailx -r << seu_e-mail@empresa.com >> -s "$MAIL_SUB" << seu_e-mail@empresa.com >>  < $ARQLOG
#
# Renomeia arquivo de log
#

cd $HOME
mv sync.txt  $HOME/logs/sync_stb.`date +%d%m%H%M`


-- Conteúdo do script checksync.sql

prompt set echo off feedback off verify off trimspool on pagesize 0 linesize 255
prompt spool $HOME/sync.txt
prompt
select 'select ''   Standby Database Seq# '||sequence#||' First Time: '||to_char(first_time,'dd/mm/yyyy hh24:mi:ss')||'''||CHR(10)||'||chr(10)||
       '       ''Production Database Seq# ''||sequence#||'' First Time: ''||to_char(first_time,''dd/mm/yyyy hh24:mi:ss'')||CHR(10)||CHR(10)||'||chr(10)||
       '       ''Diferenca de Sincronizacao (minutos): ''||round((first_time-to_date('''||to_char(first_time,'yyyymmddhh24miss')||''',''yyyymmddhh24miss''))*2
4*60)'||chr(10)||
       '  from v$log_history'||chr(10)||
       ' where sequence#=(select max(sequence#) from v$log_history)'||chr(10)||
       '/'
  from v$log_history
 where sequence# = (select max(sequence#) from v$log_history)
/

select 'set lines 200 pages 200' from dual;

select 'select process, status from v$managed_standby;' from dual;

prompt exit
spool off
exit



Script - clear_archives.sh

Script que realiza a remoção de “archives” já aplicados no banco “standby”.

Abaixo segue o código fonte:


. $HOME/.profile

export ORACLE_SID=basestd
export ORACLE_BASE=/u01/app
export ORACLE_HOME=/u01/app/oracle/ora11g

#----------------------------------------------------------
#Verifica archives a eliminar
#----------------------------------------------------------
/u01/app/oracle/ora11g/bin/sqlplus "sys/@basestd as sysdba"   @/u01/app/oracle/ora11g/bin/clear_archives.sql

-- Conteúdo do script clear_archives.sql

set head off
set pagesize 0
set feedback off
set linesize 200
set trimspool on
set echo off
spool /u01/app/oracle/ora11g/bin/clear_lista_archives.sql
select '!rm '||name from v$archived_log
where trunc(completion_time) < trunc(sysdate-1)
and   APPLIED = 'YES' and name <> 'BASESTD'
/

select 'exit;' from dual
/
spool off
@/u01/app/oracle/ora11g/bin/clear_lista_archives.sql
exit

  
Com os procedimentos acima descritos, já é possível gerenciar seu banco de dados “standby”.

Os scripts de automação, poderão ser colocado na “crontab” do usuário “oracle” para execução automatica, permitindo um controle mais efetivo do gerenciamento.



Rubens Oliveira
DBA Oracle Consultor
olivert.dba@consultant.com

segunda-feira, 14 de novembro de 2011

Oracle Standby Database 1/2


Neste artigo descreverei os procedimentos para a criação, ativação e gerenciamento de uma configuração do “standby database”.

Oracle Standby Database Conceito - O “standby database” é uma “feature” do Oracle, utilizada como plano de contingência do banco de dados. Sua arquitetura é constituída por um banco primário e um ou mais bancos secundários, versões mais recentes do Oracle são conhecidas também como Oracle Data Guard.

A principal diferença entre o “Standby” é o “Data Guard” é que o Data Guard possuí níveis maiores de configuração para a segurança da base de dados principal. Na prática alguns parâmetros podem ser ajustados para melhorar a verificação da base principal e em caso de queda ou interrupção o banco de dados secundário assume automaticamente como base principal.

Neste artigo irei descrever os passos para a criação de um banco em modo “standby”.  Este artigo será dividido em duas partes a primeira será apresentado a criação do banco e na segunda parte será apresentado gerenciamento e administração.

Segue abaixo os passos necessários para a criação de um “Standby Database”.

1.   Habilitar o banco de dados primário em FORCE LOGGING.
Executar: alter database force logging;

2.   Configurar o redo log para o “standby” no banco primário.
Executar: alter database add standby logfile group 4 size 50m;

Nota: Adicionar a quantidade de “redo logs” conforme a quantidade de “redo logs” do banco de dados primário, o comando acima serve como exemplo.


3.   Gerar o arquivo de “pfile”.
Executar: create pfile='+.ora’ from spfile;

E editar o “init.ora” e incluir os parâmetros no “init.ora” do banco primário.

*.LOG_ARCHIVE_CONFIG='DG_CONFIG=(base,basestd)'
*.LOG_ARCHIVE_DEST_1='LOCATION=/u03/oradata/base/arch/ VALID_FOR=(ALL_LOGFILES,ALL_ROLES) DB_UNIQUE_NAME=base'
*.LOG_ARCHIVE_DEST_2='SERVICE=basestd LGWR ASYNC VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE) DB_UNIQUE_NAME=basestd'
*.LOG_ARCHIVE_DEST_STATE_1=ENABLE
*.LOG_ARCHIVE_DEST_STATE_2=ENABLE
*.LOG_ARCHIVE_FORMAT=arch_%r_%t_%s.arc
*.LOG_ARCHIVE_MAX_PROCESSES=30
*.fal_server=BASE
*.fal_client=BASESTD
*.standby_file_management=auto

4.   Recriar o arquivo “spfile” do banco de dados primário.
Executar: create spfile  from pfile='+.ora’;

5.   Verificar o “archives” antes da cópia.
Executar: Archive log list;

6.   Colocar o banco de dados primário em “begin backup”.
Executar : alter database begin backup;

7.   Copiar os datafiles e tempfiles para o servidor DESTINO.

Executar a query abaixo, para gerar o comando que irá realizar a cópia dos datafiles:

select 'scp '||substr(file_name,1,43)||' 100.107.10.153:'||substr(file_name,1,43)
  from dba_data_files
 order by 1;

Executar a query abaixo, para gerar o comando que irá realizar a cópia dos tempfiles:

select 'scp '||substr(file_name,1,43)||' 100.107.10.153:'||substr(file_name,1,43)
  from dba_temp_files

Nota: Substituir o endereço IP para o endereço do seu servidor (endereço meramente ilustrativo).

8.   Ao término das cópias dos datafiles e tempfiles retirar o banco de dados primário do status de  “end backup”.
Executar : alter database end backup;

9.   Verificar o “archives” depois da cópia.
Executar : archive log list;

10. Gerar um “control file standby” no banco de primário.
Executar: alter database create standby controlfile as '/';

11. Copiar o “control file” do servidor primário para o servidor do “standby” .
Executar:
 scp /home/oracle/control_stdby.ctl 100.107.10.153:/home/oracle/control_stdby.ctl

Nota: Após a cópia do “control file” de STANDBY copiar os “control files” para as cópias existentes, abaixo segue um exemplo:

copy control_stdby.ctl contro01.ctl
copy control_stdby.ctl contro02.ctl
copy control_stdby.ctl contro03.ctl

12. Copiar os “redo logs” do servidor primário para o servidor secundário.
Executar:
select 'scp '||substr(member,1,33)||' 100.107.10.153:'||substr(member,1,33)
  from v$logfile order by 1;

13. Copiar os arquivos de “init.ora”, “spfiles”, “orapwd”,”listener”, “tnsnames”, “sqlnet”.
Executar:
scp /u01/app/oracle/ora11/dbs/initbase.ora 
100.107.10.153:/u01/app/oracle/ora11/dbs/initbase.ora

scp /u01/app/oracle/ora11/dbs/spfilebase.ora 
100.107.10.153:/u01/app/oracle/ora11/dbs/spfilebase.ora

scp /u01/app/oracle/ora11/dbs/orapwbase
100.107.10.153:/u01/app/oracle/ora11/dbs/orapwbase

scp /u01/app/oracle/ora11/network/admin/listener.ora
100.107.10.153:/u01/app/oracle/ora11/network/admin/listener.ora

scp /u01/app/oracle/ora11/network/admin/tnsnames.ora 100.107.10.153:/u01/app/oracle/ora11/network/admin/tnsnames.ora

scp /u01/app/oracle/ora11/network/admin/sqlnet.ora
100.107.10.153:/u01/app/oracle/ora11/network/admin/sqlnet.ora

14. Verificar os caminhos dos parâmetros, control_files, log_archive_dest(n) no banco “standby”.

15. Criar o arquivo “pfile” para o “standby” a partir do banco de dados primário.
Executar: create pfile='+.ora’ from spfile;

16.  Ajustar os arquivos TNSNAMES.ora nos servidores primários e “standby”.
Incluir as entradas abaixo:

base  =
(description =
   (address_list =
      (address=(protocol=tcp)(host=100.117.20.143)(port=1521))
      (ADDRESS = (PROTOCOL = TCP)(HOST = 100.117.20.143)(PORT = 1525))
      (ADDRESS = (PROTOCOL = TCP)(HOST = 100.117.20.143)(PORT = 1526))
      (ADDRESS = (PROTOCOL = TCP)(HOST = 100.117.20.143)(PORT = 1527))
      (ADDRESS = (PROTOCOL = TCP)(HOST = 100.117.20.143)(PORT = 1528))
      )
   (connect_data=(sid=base)))

basestd  =
(description =
   (address_list =
      (address=(protocol=tcp)(host=100.107.10.153)(port=1521))
      (ADDRESS = (PROTOCOL = TCP)(HOST = 100.107.10.153)(PORT = 1525))
      (ADDRESS = (PROTOCOL = TCP)(HOST = 100.107.10.153)(PORT = 1526))
      (ADDRESS = (PROTOCOL = TCP)(HOST = 100.107.10.153)(PORT = 1527))
      (ADDRESS = (PROTOCOL = TCP)(HOST = 100.107.10.153)(PORT = 1528))    
      )
   (connect_data=(sid=base)))

17.  Ajustar o arquivo LISTENER.ora, incluir a entrada do banco de dados “standby”.

SID_LIST_LISTENER =
  (SID_LIST =
    (SID_DESC =
      (SID_NAME = PLSExtProc)
      (ORACLE_HOME = /u01/app/oracle/ora11)
      (PROGRAM = extproc)
    )

    (SID_DESC =
      (SID_NAME = base)
      (GLOBAL_DBNAME = basestd)
      (ORACLE_HOME = /u01/app/oracle/ora11)
    )
  )

LISTENER =
  (DESCRIPTION_LIST =
    (DESCRIPTION =
      (ADDRESS = (PROTOCOL = TCP)(HOST = 100.107.10.153)(PORT = 1521))
      (ADDRESS = (PROTOCOL = TCP)(HOST = 100.107.10.153)(PORT = 1525))
      (ADDRESS = (PROTOCOL = TCP)(HOST = 100.107.10.153)(PORT = 1526))
      (ADDRESS = (PROTOCOL = TCP)(HOST = 100.107.10.153)(PORT = 1527))
      (ADDRESS = (PROTOCOL = TCP)(HOST = 100.107.10.153)(PORT = 1528))
    )
  )

18.  Validar as conexões do banco primário para o “standby”, via sistema operacional executar:
 tnsping basestd

19.  Validar as conexões do banco “standby” para o primário, via sistema operacional executar:
tnsping base

20.  Levantar e montar o banco de dados “standby”.
Executar:
startup nomount;
alter database mount standby database;

21.  Ativar a atualização automática do “standby”.
Executar:
alter database recover managed standby database disconnect from session;


A partir desse comando o banco de dados “standby”está configurado, no próximo artigo estarei demonstrando como gerenciar um banco “standby”.



Rubens Oliveira
DBA Oracle Consultor
olivert.dba@consultant.com