sexta-feira, 9 de março de 2012

Restaurando DBF no Oracle XE


Numa infeliz ocorrência minha máquina parou de funcionar e eu não possuía as versões mais novas do banco de dados (Oracle XE), após várias pesquisas na net encontrei alguns usuários dizendo que a restauração seria impossível e outros com tentativas frustrantes, mas persisti e tive um resultado feliz, consegui restauras todas as instâncias do banco em uma nova instalação do Oracle XE e numa máquina diferente, abaixo seguem os passos realizados:
Para salvar a base de dados foi feita uma cópia de toda a pasta OracleXE para a outra chamada OracleXE_BKP.



1. Parar os serviços do Oracle:

OracleServiceXE
OracleXETNSListener
2. Guardando uma cópia dos arquivos originais da instalação (Apenas por segurança)
    • Vá até a pasta C:\oraclexe\app\oracle\product\10.2.0\server\NETWORK\ADMIN, recorte os arquivos:
      SQLNET.ORA

      TNSNAMES.ORA
      LISTENER.ORA
      Crie uma pasta chamada ORIGINAL e cole estes arquivos nesta pasta;

    • Vá até a pasta C:\oraclexe\app\oracle\flash_recovery_area\XE\ONLINELOG, recorte todos os arquivos desta pasta, crie uma pasta chamada ORIGINAL e cole estes arquivos nesta pasta;
    • Vá até a pasta C:\oraclexe\app\oracle\product\10.2.0\server\dbs, recorte todos os arquivos desta pasta, crie uma pasta chamada ORIGINAL e cole estes arquivos nesta pasta;
    • Vá até a pasta C:\oraclexe\app\oracle\product\10.2.0\server\config\scripts, recorte o arquivo INIT.ORA, crie uma pasta chamada ORIGINAL e cole este arquivo nesta pasta;
    • Vá até a pasta C:\oraclexe\oradata\XE, recorte todos os arquivos desta pasta, crie uma pasta chamada ORIGINAL e cole estes arquivos nesta pasta.
 3. Restaurando os arquivos

Como a restauração foi feita em uma nova máquina então tive que alterar o HOST dos arquivos abaixo:

          TNSNAMES.ORA
    LISTENER.ORA
    INIT.ORA

** Atenção: Verifique a porta de instalação do Oracle, pois ela pode ser diferente entre as instalações.

TNSNAMES.ORA 
XE =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = [novo_hostname])(PORT = 1522))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = XE)
)
)
Verifiquem todas as instâncias que utilizam o HOST antigo, pois elas devem ser alteradas.

LISTENER.ORA 
LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC_FOR_XE))
(ADDRESS = (PROTOCOL = TCP)(HOST = [novo_hostname])(PORT = 1522))
)
)

INIT.ORA 
local_listener="(ADDRESS=(PROTOCOL=TCP)(HOST=[novo_hostname])(PORT=1522))"

Copiando arquivos da base antiga (OracleXE_BKP) para a nova instalação do Oracle
  • Copie os arquivos abaixo da pasta C:\oraclexe_bkp\app\oracle\product\10.2.0\server\NETWORK\ADMIN para a pasta C:\oraclexe\app\oracle\product\10.2.0\server\NETWORK\ADMIN
       SQLNET.ORA
       TNSNAMES.ORA
       LISTENER.ORA

  • Copie todos os arquivos da pasta C:\oraclexe_bkp\app\oracle\flash_recovery_area\XE\ONLINELOG para a pasta C:\oraclexe\app\oracle\flash_recovery_area\XE\ONLINELOG
  • Copie todos os arquivos da pasta C:\oraclexe_bkp\app\oracle\product\10.2.0\server\dbs para a pasta pasta C:\oraclexe\app\oracle\product\10.2.0\server\dbs
  • Copie o arquivo INIT.ORA da pasta C:\oraclexe_bkp\app\oracle\product\10.2.0\server\config\scripts para a pasta pasta C:\oraclexe\app\oracle\product\10.2.0\server\config\scripts
  • Copie todos os DBFs da pasta C:\oraclexe_bkp\oradata\XE para a pasta C:\oraclexe\oradata\XE


4. Reinicie os serviços do Oracle


OracleServiceXE
OracleXETNSListener


5. Acesse o Oracle


Tente conectar a uma das instâncias, no meu caso ocorreu erro de senha, então conectei como SYSDBA e alterei as senhas de todas as instâncias.

A partir daí tudo funcionou perfeitamente.
Espero ter ajudado.

quinta-feira, 8 de março de 2012

Utilizando Bulk Collect no Oracle

Uma forma eficiente para manipularmos grandes quantidades de dados pode ser a utilização de BULK COLLECT. Se utilizarmos corretamente, podemos ter um grande ganho no desempenho das aplicações, pois os dados manipulados pelas coleções ficam armazenados diretamente na memória. Por outro lado, podemos ter problemas se os limites para a quantidade de dados carregados em memória não for dimensionado corretamente. Para cada sessão de usuário, o Oracle alocará espaço em uma área de memória chamada PGA (Program Global Area). Se tivermos 100 usuários conectados simultaneamente utilizando os recursos uma coleção que ocupa 10Mb em memória, teremos um consumo total de 1Gb!
Felizmente podemos limitar os dados que são armazenados nas coleções usando a clausula LIMIT. Desta forma, podemos analisar a relação custo/benefício concedendo limites maiores ou menores para nossa coleção.

É importante lembrar que do Oracle Database 10g em diante os cursores (FOR LOOPS) são automaticamente otimizados para velocidades próximas as do BULK COLLECT.

Vamos ver na prática como tudo isso funciona.

Criar tabela teste:

create table tab19x (id number(5),
                     nome varchar2(30),
                     constraint tab19x_pk primary key (id));

Popular a tabela:
begin
  insert into tab19x

  select level, dbms_random.string(‘a’, 30) from dual connect by level <= 123; 
  commit;
end;

Abaixo temos um bloco de código PL/SQL anônimo, onde temos um BULK COLLECT limitando a coleção para 50 registros. Isso significa que cada vez que os dados são lidos do cursor, no máximo 50 registros por vez são alocados na memória. Toda vez que a coleção for carregada, uma mesma quantidade de memória será alocada na PGA, mesmo que a tabela aumente de tamanho em número de linhas.

Utilizando o BULK COLLECT

declare
  cursor cur_tab19x is
                    select id, nome from tab19x;
--Abaixo crio o tipo para a coleção type trow_tab19x is table of cur_tab19x%rowtype index by pls_integer;

--Declaro a coleção row_tab19x row_tab19x trow_tab19x;

begin  open cur_tab19x;
    loop
    fetch cur_tab19x BULK COLLECT
     into row_tab19x limit 50;
   
    --NÃO use :exit when cur_tab19x%notfound;
    exit when row_tab19x.count = 0;
    for i in 1 .. row_tab19x.count
    loop

       dbms_output.put_line(‘Cod :‘ || row_tab19x(i).id || ‘ valor:‘ || row_tab19x (i).nome);    end loop;
  end loop;
  close cur_tab19x;

end;

Quando utilizamos BULK COLLECT precisamos lembrar que:
  • As coleções são preenchidas sequencialmente, iniciando do índice valor 1;
  • Interagir com a coleção de 1 até coleção.COUNT;
  • A coleção é vazia quando não tivermos mais linhas depois de um fetch;
  • Sempre utilize o método coleção.COUNT para ver se existem mais linhas para serem processadas;
  • Ignore os valores retornados pelos atributos do cursor, especialmente o cursor%NOTFOUND;
Fonte: http://www.oracle.com/technology/oramag/oracle/08-mar/o28plsql.html

Utilizando cursores no Oracle

Olá, pessoal!
Neste artigo vamos simular a utilização dos diversos tipos de cursores no Oracle, por final vamos comparar a velocidade destes. Utilizaremos a extração de uma tabela com uma massa de dados de 50 mil registros para que possamos fazer um teste considerável.

01. Criar tabela

Crie a estrutura da tabela
create table TB_PESSOA
(
  IDPESSOA       INTEGER not null,
  NOME           VARCHAR2(40) not null,
  DATANASCIMENTO DATE not null,
  ALTURA         NUMBER(5,2),
  PESO           NUMBER(5,2)
)

02. Inserir registros

Vamos inserir 50 mil registros na tabela para criarmos um volume de dados considerável para nossos testes.
declare

v_id_pessoa tb_pessoa.idpessoa%type;
v_nome      tb_pessoa.nome%type;
v_dt_nascimento tb_pessoa.datanascimento%type;
begin

v_nome := 'Joao da Silva';
v_dt_nascimento := to_date('01/01/1900');

  for dd in 1..50000 loop
  
      
     select nvl(max(p.idpessoa),0)+1
       into v_id_pessoa
       from tb_pessoa p;
     
    insert into tb_pessoa(idpessoa,nome,datanascimento)
                   values(v_id_pessoa,v_nome,v_dt_nascimento);
    
  end loop;

end;


commit;

03. Criação dos objetos

Vamos criar as procedures com as seguintes formas de cursores. Vejam que em todas temos as variáveis v_dt_inicio e v_dt_fim, que farão o controle do tempo de processamento da procedure.
3.1. O cursor contido nesta procedure é o mais usual. O cursor de tipo pré-declarado
Procedure PRC_TST_CURSOR

create or replace procedure prc_tst_cursor is

v_dt_inicio timestamp;
v_dt_fim    timestamp;

cursor cr_pessoa is
select *
  from tb_pessoa;

v_pessoa cr_pessoa%rowtype;

begin

v_dt_inicio := systimestamp;

  open cr_pessoa;
   loop
   fetch cr_pessoa into v_pessoa;
   exit when cr_pessoa%notfound;
     null;
   end loop;
  close cr_pessoa;

v_dt_fim := systimestamp;

dbms_output.put_line('Tempo processamento: '||to_char(v_dt_fim - v_dt_inicio,'dd/mm/yyyy hh24:mi:ss.ff'));

end;
3.2. Esta procedure abaixo contém uma forma de cursor bastante utilizada também. O cursor do tipo for é um dos de mais fácil de utilização.
Procedure PRC_TST_FOR

create or replace procedure prc_tst_for is

v_dt_inicio timestamp;
v_dt_fim    timestamp;

begin

v_dt_inicio := systimestamp;

  for dd in (select p.idpessoa
               from tb_pessoa p) loop

     null;

   end loop;

v_dt_fim := systimestamp;

dbms_output.put_line('Tempo processamento: '||to_char(v_dt_fim - v_dt_inicio,'dd/mm/yyyy hh24:mi:ss.ff'));

end;
3.3. Nesta procedure abaixo, temos a extração da informação através de um bulk collection. Forma menos usual, alguns front end não suportam este tipo de cursor, que é o caso do FORMS.
Procedure PRC_TST_BULK_COUNT

create or replace procedure prc_tst_bulk_count is

v_dt_inicio timestamp;
v_dt_fim    timestamp;

type typ_pessoa is table of tb_pessoa%rowtype;
v_tb_pessoa typ_pessoa;

begin

v_dt_inicio := systimestamp;

  select *
    bulk collect into v_tb_pessoa
    from tb_pessoa;

   for dd in 1..v_tb_pessoa.count loop

     null;

   end loop;


v_dt_fim := systimestamp;

dbms_output.put_line('Tempo processamento: '||to_char(v_dt_fim - v_dt_inicio,'dd/mm/yyyy hh24:mi:ss.ff'));

end;
3.4. Nesta procedure abaixo, temos a variação do cursor de bulk collection, onde a diferença está apenas na execução do loop.
Procedure PRC_TST_BULK_FIRST_LAST

create or replace procedure prc_tst_bulk_first_last is

v_dt_inicio timestamp;
v_dt_fim    timestamp;

type typ_pessoa is table of tb_pessoa%rowtype;
v_tb_pessoa typ_pessoa;

begin

v_dt_inicio := systimestamp;

  select *
    bulk collect into v_tb_pessoa
    from tb_pessoa;

   for dd in v_tb_pessoa.first.. v_tb_pessoa.last loop

     null;

   end loop;


v_dt_fim := systimestamp;

dbms_output.put_line('Tempo processamento: '||to_char(v_dt_fim - v_dt_inicio,'dd/mm/yyyy hh24:mi:ss.ff'));

end;
Para a execução das procedures utilizei o PL/SQL Developer, para isso você pode utilizar qualquer programa, SQL*Plus, TOAD, SQL Developer dentre outros.


Chamada da procedure prc_tst_cursor.


Tempo de execução prc_tst_cursor.


Chamada da procedure prc_tst_for.


Tempo de execução prc_tst_for.


Chamada da procedure prc_tst_bulk_count.


Tempo de execução prc_tst_bulk_count.


Chamada da procedure prc_tst_bulk_first_last.


Tempo de execução prc_tst_bulk_first_last.

ProcedureTempo Execução
PRC_TST_CURSOR953 Milésimos
PRC_TST_FOR844 Milésimos
PRC_TST_BULK_COUNT109 Milésimos
PRC_TST_BULK_FIRST_LAST 109 Milésimos

Conclusões

Velocidade
Com isso, conseguimos provar que a análise do cursor explicito (FETCH) é o mais lento levando 953 Milésimos para sua execução, seguido do cursor implícito (FOR) com 844 Milesimos.
E em primeiro lugar cursores de BULK COLLECT. Independente da forma de extração dos dados de dentro do cursor, da montagem do loop, sendo via COUNT ou via FIRST-LAST, são os mais rápidos ambas as formas levando 109 Milésimospara seu processamento.
Facilidade de Implementação
No ponto de vista de implementação dos cursores, o FOR é os mais simples, bastando ser declarado ao longo do programa. Os cursores de BULK COLLECT vêm segundo lugar, pois necessitam que sejam declarados variáveis baseadas em types, tornando a implementação pouca coisa mais trabalhosa. Já os cursores de FETCH vêm em último lugar. Como devem ser declarados juntamente com as variáveis que receberão os valores, além de que devem abertos ao longo da execução do programa e fechados, sua implementação torna-se mais trabalhosa.
Documentação
Todos os cursores podem ser documentados com facilidade. Por sintaxe o cursor de FETCH deve receber obrigatoriamente um nome em sua declaração, tornando a documentação automática. Os outros cursores também podem ser nomeados, mas não é muito comum de ver esse tipo de coisa.

Conclusão Final

Com base na velocidade, o mais importante, nas facilidades de implementação e documentações. Concluo que em primeiro lugar por conter a execução mais rápida e estar em segundo lugar em facilidade de implementação o cursor de BULK COLLECT é o melhor a ser utilizado para uma massa de dados grande.
Considero também que os outros cursores também são de grande utilização, mas para massas de dados menores.

Fonte: http://imasters.com.br/artigo/12960/oracle/utilizando_cursores_no_oracle/
Related Posts Plugin for WordPress, Blogger...