Pesquisar

Quem sou eu

Minha foto
Formado em Tecnologia de Processamento de Dados pela FESP-Paraná. Pós-graduado em Administração em Informática e Administração de Banco de Dados pela FESP-Paraná. Certificação ORACLE/OCA e DB2 9 Family Fundamentals.

sábado, 14 de agosto de 2010

SQL TUNING: UNION X CASE

Olá!

Não é fato extraordinário encontrar códigos SQLs com querys complexas fazendo uso do operador UNION. Esta forma de codificação pode gerar graves problemas de performance.

Uma alternativa para estes casos, é substituir o operador UNION pela expressão CASE.

Vamos ver um exemplo típico.

O SQL abaixo utiliza o operador UNION para exibir dados de parcelas com seus respectivos STATUS.

select P.NM_CONTRAT CONTRATO,
P.NM_LIBERAC LIBERACAO,
P.NM_PARCELA PARCELA,
'ABERTA' SITUACAO
from PARCELAS P
where P.LG_BAIXADO = 'F'
and P.DT_CADASTR between '02/01/2010' and '05/01/2010'
union
select P.NM_CONTRAT CONTRATO,
P.NM_LIBERAC LIBERACAO,
P.NM_PARCELA PARCELA,
'BAIXADA' SITUACAO
from PARCELAS P
where P.LG_BAIXADO = 'T'
and P.DT_CADASTR between '02/01/2010' and '05/01/2010';

Olhando-se para o plano de execução abaixo nota-se que, apesar do uso de um índice sobre a coluna DT_CADASTR para acessar os dados, a tabela PARCELAS é acessada 2 vezes por causa do operador UNION.


Decorrido: 00:00:02.37

Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=224 Card=9856 Bytes=236544)
1 0 SORT (UNIQUE) (Cost=224 Card=9856 Bytes=236544)
2 1 UNION-ALL
3 2 TABLE ACCESS (BY INDEX ROWID) OF 'CG_PARCE' (Cost=88 Card=4928 Bytes=118272)
4 3 INDEX (RANGE SCAN) OF 'CG_PARCE_DT_CADASTR' (NON-UNIQUE) (Cost=29 Card=4928)
5 2 TABLE ACCESS (BY INDEX ROWID) OF 'CG_PARCE' (Cost=88 Card=4928 Bytes=118272)
6 5 INDEX (RANGE SCAN) OF 'CG_PARCE_DT_CADASTR' (NON-UNIQUE) (Cost=29 Card=4928)


Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
12 consistent gets
0 physical reads
0 redo size
1628 bytes sent via SQL*Net to client
536 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
3 sorts (memory)
0 sorts (disk)
24 rows processed

Agora, vamos reescrever o SQL substituindo o UNION pela expressão CASE:

select P.NM_CONTRAT CONTRATO,

P.NM_LIBERAC LIBERACAO,
P.NM_PARCELA PARCELA,
CASE
WHEN P.LG_BAIXADO = 'F' THEN
'ABERTA'
WHEN P.LG_BAIXADO = 'T' THEN
'BAIXADA'
ELSE
'NAO DEFINIDA'
END SITUACAO
from PARCELAS P
where P.DT_CADASTR between '02/01/2010' and '05/01/2010';

O plano de execução abaixo mostra que a reescrita do SQL reduziu 50% o uso de recursos do banco de dados acessando a tabela PARCELAS uma única vez. Além disso, ela executa apenas 30% dos sorts em memória em relação ao comando escrito com UNION.

Decorrido: 00:00:02.62


Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=88 Card=9856 Bytes=236544)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'CG_PARCE' (Cost=88 Card=9856 Bytes=236544)
2 1 INDEX (RANGE SCAN) OF 'CG_PARCE_DT_CADASTR' (NON-UNIQUE) (Cost=29 Card=9856)

Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
10 consistent gets
0 physical reads
0 redo size
2096 bytes sent via SQL*Net to client
536 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
24 rows processed
 
Portanto, o CASE é uma ótima alternativa ao uso do UNION para codificar querys com melhor performance.


Até a próxima.

domingo, 11 de julho de 2010

ACESSO COM TEMPO LIMITADO

Olá.


Para análise de erros em aplicações, desenvolvedores, muitas vezes, necessitam pelo menos de acesso leitura aos bancos de dados de produção. A boa prática para esses casos é o DBA criar um usuário específico para essa atividade atribuindo-lhe somente os privilégios CREATE SESSION, SELECT sobre as tabelas da aplicação. Em seguida, liberar este usuário para os desenvolvedores.


Melhor prática ainda, é manter a conta deste usuário sempre bloqueada e liberá-la somente quando houver uma solicitação/autorização formal (e-mail ou documento) para acesso aos dados de produção. Parece burocrático, mas mantém documentado e registrado todo acesso ao banco de dados.


Pensando nisto, implementei um processo que libera o acesso por um determinado tempo (1h por exemplo) para que sejam feitas consultas aos dados do banco de dados de produção. Após certo tempo, o acesso é bloqueado e todas as sessões do usuário são desconectadas.


Chega de explicações e vamos ao processo:

Passo 1: Partindo do pressuposto de que o usuário de acesso leitura já tenha sido criado, a primeira etapa é desenvolver uma procedure que vai executar as tarefas de desbloquear o usuário com acesso somente leitura e agendar um job no banco de dados. Este job vai executar uma outra procedure que faz o caminho inverso, ou seja, bloqueia novamente o usuário de leitura e executa os KILL SESSIONs de sessões. Isso mesmo, utilizei um simples job para auxiliar neste processo.

Abaixo, o código da procedure que libera o acesso e agenda o job:

CREATE OR REPLACE PROCEDURE prcLiberaAcessoAProducao(parUSUARIO VARCHAR2)
IS


intCURSOR INTEGER;
intPROCESSED INTEGER;
numJOB NUMBER;
numJOBNO NUMBER;
varWHAT VARCHAR2(100);
varUSUARIO VARCHAR2(100);

BEGIN

   varUSUARIO := UPPER(parUSUARIO);
   varWHAT := 'prcBloqueiaAcessoAProducao(' || CHR(39) || varUSUARIO || CHR(39) || ');';

   --desbloqueia o usuario
   intCURSOR := DBMS_SQL.OPEN_CURSOR;
   DBMS_SQL.PARSE(intCURSOR, 'ALTER USER ' || UPPER(parUSUARIO) || ' ACCOUNT UNLOCK', DBMS_SQL.NATIVE);
   intPROCESSED := DBMS_SQL.EXECUTE(intCURSOR);
   DBMS_SQL.CLOSE_CURSOR(intCURSOR);

   -- agenda job para bloquear usuario em 1 hora
   BEGIN

      SELECT job INTO numJOB
      FROM DBA_JOBS
      WHERE what LIKE '%' || varWHAT || '%';

      -- atualiza job
      DBMS_JOB.NEXT_DATE(job=>numJOB, next_date=>SYSDATE + 1/24);
      DBMS_OUTPUT.PUT_LINE('*** JOB de bloqueio do usuario ' || varUSUARIO || ' alterado com sucesso! ***');
      DBMS_OUTPUT.PUT_LINE('*** Tempo disponivel para acesso ao usuario ' || UPPER(parUSUARIO) || ' expira    em 1h! ***');

   EXCEPTION
      -- insere job
      WHEN no_data_found THEN
      DBMS_JOB.SUBMIT(job=>numJOBNO, what=>varWHAT, next_date=>SYSDATE + 1/24);
      DBMS_OUTPUT.PUT_LINE('*** JOB de bloqueio do usuario ' || varUSUARIO || ' inserido com sucesso! ***');
      DBMS_OUTPUT.PUT_LINE('*** Tempo disponivel para acesso ao usuario ' || varUSUARIO || ' expira em 1h! ***');


   END;

END;
/

A procedure recebe o parâmetro usuário. Portanto, pode ser executada para qualquer usuário do banco de dados.

Passo 2:. A etapa seguinte é desenvolver uma outra procedure que, após 1h, vai ser executada via job bloqueando a conta do usuário leitura e desconectando as sessões deste usuário.

Abaixo, o código:

CREATE OR REPLACE PROCEDURE prcBloqueiaAcessoAProducao(parUSUARIO VARCHAR2)
IS

intCURSOR INTEGER;
intPROCESSED INTEGER;
varSID VARCHAR2(100);
varSERIAL VARCHAR2(100);
varUSUARIO VARCHAR2(100);

BEGIN

    varUSUARIO := UPPER(parUSUARIO);   
    -- bloqueia o usuario
    intCURSOR := DBMS_SQL.OPEN_CURSOR;
    DBMS_SQL.PARSE(intCURSOR, 'ALTER USER ' || varUSUARIO || ' ACCOUNT LOCK', DBMS_SQL.NATIVE);
    intPROCESSED := DBMS_SQL.EXECUTE(intCURSOR);
    DBMS_SQL.CLOSE_CURSOR(intCURSOR);
   
    -- desconecta sessoes do usuario no banco de dados de producao
    FOR reg_cursor_killsession IN (SELECT sid, serial#
                                   FROM v$session
                                   WHERE username = varUSUARIO)
    LOOP
        varSID := TO_CHAR(reg_cursor_killsession.sid);
        varSERIAL := TO_CHAR(reg_cursor_killsession.serial#);
        intCURSOR := DBMS_SQL.OPEN_CURSOR;
        DBMS_SQL.PARSE(intCURSOR, 'ALTER SYSTEM KILL SESSION ''' || varSID || ',' || varSERIAL || ''' IMMEDIATE', DBMS_SQL.NATIVE);
        intPROCESSED := DBMS_SQL.EXECUTE(intCURSOR);
        DBMS_SQL.CLOSE_CURSOR(intCURSOR);
    END LOOP;

EXCEPTION
    WHEN OTHERS THEN
        DBMS_SQL.CLOSE_CURSOR(intCURSOR);
END;
/


Com as procedures criadas, agora basta apenas executar a procedure prcLiberaAcessoAProducao toda vez que for solicitado acesso aos dados da produção.

Até a próxima.


domingo, 6 de junho de 2010

COMO BLOQUEAR CONEXÕES DE APLICATIVOS?

Olá !!!

O assunto que escolhi para compartilhar com vocês neste mês, é como implementar uma forma de bloqueio das conexões de alguns programas à instância de banco de dados.

É um processo relativamente simples e muito útil se você deseja restringir conexões de programas como SQLPLUS, TOAD, SQLDEVELOPER, PLSQL DEVELOPER, EXCEL, MSACCESS, etc. ao banco de dados.

Para a implementação do controle de acesso, criei uma trigger que dispara no evento "AFTER LOGON" do banco de dados.

Vamos ao código PL/SQL:


CREATE OR REPLACE TRIGGER "SYS"."AUDIT_LOGON" AFTER
LOGON ON DATABASE


DECLARE

v_sid number;
v_program varchar2(64);
v_msg varchar2(200);




BEGIN

EXECUTE IMMEDIATE 'SELECT DISTINCT sid FROM sys.v_$mystat'
INTO v_sid;

EXECUTE IMMEDIATE 'SELECT program FROM sys.v_$session WHERE sid = :b1'
INTO v_program
USING v_sid;

v_msg := 'Tentativa de conexao com: ' ||v_program||' recusada!!!';

-- programas bloqueados
IF (UPPER(v_program) LIKE '%TOAD%' OR
    UPPER(v_program) LIKE '%PLSQLDEV%' OR
    UPPER(v_program) LIKE '%MSACCESS%' OR
    UPPER(v_program) LIKE '%EXCEL%' OR
    UPPER(v_program) LIKE '%PLUS%') THEN



    RAISE_APPLICATION_ERROR(-20000,v_msg,true);



END IF;



END;
 
A vantagem deste código é a possibilidade de combinar IF ... END IF para restringir vários tipos de acesso. Por exemplo, você pode restringir acesso de algumas máquinas de seu ambiente de homologação através da coluna MACHINE da V$SESSION. Ou ainda, restringir o acesso de alguns usuários de rede através da coluna OSUSER também presente na V$SESSION. Enfim, a combinação de condições de acesso fica a seu critério.
 
Vale lembrar que, o usuário SYS sempre vai conseguir logar com sucesso no banco de dados via qualquer programa independentemente da existência ou não de uma trigger com estas características.
 
Até a próxima.

segunda-feira, 24 de maio de 2010

COMO MELHORAR A PERFORMANCE DE INSERT

Olá !

Durante este mês, passei alguns dias analisando um problema de performance que ocorreu em uma das rotinas de fechamento mensal da aplicação de um de meus clientes. O problema era o seguinte: durante a rotina, um dos programas executa uma série de INSERTS com SELECT FULL dos dados das tabelas origem para outras tabelas da aplicação. Isto é feito mensalmente desde (aguarde um minuto pois estou pegando o MIN de uma data da tabela ... hehehe) o mês 5/2006. Duas destas tabelas tem uma média de 2 milhões de registros/mês. Ou seja, após quase 4 anos, a tabela que armazena uma cópia mensal destes dados acumulou mais de 100 milhões de registros. Juntem a isso, mas 3 índices criados para acesso aos dados destas tabelas ... Como diria Milton Leite: que belezaaaa hein? ... Não é do nada que a performance dos INSERTs está horrível ...

Bem, deixando de lado esta indignação com o problema, vem a pergunta: Como otimizar estas operações sobre estas tabelas?

A primeira, e mais sensata idéia, porém a longo prazo, é questionar desenvolvedores e usuários sobre qual a utilidade destes dados e a real necessidade de serem armazenados integralmente todo o mês. Ainda, não podemos estipular uma política de backup e mantermos apenas os dados do último ano, por exemplo? Essas são algumas medidas que podem ser implementadas e que ajudarão a resolver o problema sem recorrer as features do Oracle para eliminar o problema de performance.

Caso os usuários demorem um pouco a responder, a solução mais rápida é partir para recursos do ORACLE que possam melhorar a performance.

Vamos a elas então ...

A primeira análise que fiz, foi verificar a configuração do parâmetro DB_FILE_MULTIBLOCK_READ_COUNT cuja influência no otimizador e nos tempos para executar FULL TABLE SCAN é muito grande. Este parâmetro, no meu caso, estava com configuração de valor 8 e imediatamente o modifiquei para 32. Vale lembrar que este parâmetro é dinâmico, então sua configuração já passa a ser utilizada para novas sessões no BD.

Feito isso, fui atrás de features que poderiam melhorar a performance dos INSERTS. Recorri, no manual Design And Tuning for Performance, à hint PARALLEL do Oracle. Seu uso paraleliza a operação de INSERT utilizando o número de server process desejado para execução do comando. No meu caso, utilizei o grau de paralelismo 8 coincidindo com o número de núcleos de processamento do servidor de banco de dados.

Exemplo do comando: 

INSERT /*+ PARALLEL(my_target_table, 8) */ into my_target_table
(select * from my_source_table);

Para a minha surpresa o comando que, antes levava 6h para concluir, passou a ser executado em 15min. Isso mesmo, 15min !!!!
Isso demonstra o poder e versatilidade das features do Oracle. A simples adição de uma HINT no comando pode trazer resultados fantásticos de performance !!!

Até a próxima.

sábado, 15 de maio de 2010

DBLinks

Olá!

Vou falar de um tema que, na maioria das vezes, causa muita confusão para usuários e desenvolvedores, mas que na verdade não se trata de um "bicho de sete cabeças": DBLINKS. Depois de um certo tempo trabalhando com esses objetos, você acaba descobrindo que não são componentes tão complicados assim e que, na verdade, podem ser ótimos para controlar o acesso a objetos de uma outra instância.

Para familiarizar-se com o tema, primeiramente vamos entender o conceito e alguns dos tipos de  DBLinks existentes: um Database Link é um objeto do esquema em um banco de dados que possibilita você acessar objetos em um outro banco de dados. Detalhe importante: o banco de dados destino não precisa ser um RDBMS Oracle.

Consistem de 2 tipos:

PÚBLICO - Todos os usuários do BD conseguem ter acesso ao DBLink;
PRIVADO - Somente o OWNER do DBLink consegue acessá-lo.

Exemplo de como criar um Database Link:

Público

CREATE PUBLIC DATABASE LINK 'MeuDBLNK'
CONNECT TO 'user1' IDENTIFIED BY 'senha'
USING 'MeuBD'

Este DBLINK terá o nome 'MeuDBLNK', conectará no usuário 'user' cuja senha é 'senha' do banco de dados 'MeuBD'. Este objeto poderá ser acessado por todos os usuários do banco de dados.


Privado

CREATE DATABASE LINK 'MeuDBLNK'
CONNECT TO 'user1' IDENTIFIED BY 'senha'
USING 'MeuBD'

Para criar um DBLINK privado, apenas removemos a palavra-chave PUBLIC e esse DBLINK estará acessível apenas pelo o usuário OWNER do objeto.

Ok, mas como podem ser ótimos controladores de acesso conforme eu havia informado no primeiro parágrafo do texto?

Percebam que o DBLINK, tanto o público quanto o privado, conectam na instância 'MeuBD' através do usuário 'USER1'. Desta forma, quem utilizá-los só poderá acessar objetos na instância MeuBD que USER1 consegue acessar. Parece óbvio certo? Mas já cansei de ver DBLINKS PÚBLICOS conectando em instâncias diretamente no usuário/esquema OWNER de todos os objetos de uma aplicação, ou seja, deixando a aplicação inteira escancarada para todos os usuários que conseguem acessar o DBLINK.

Baseado nisso, recomendo a todos que criem na instância destino um usuário exclusivo para conectar DBLINKS e atribuam somente os privilégios necessários, e nada mais do que isso.

Existem mais tipos de DBLINKS que não citei no texto. Portanto, vale a pena uma consulta ao manual SQL da Oracle para conhecer todas as versatilidades de acesso desses objetos.

Até a próxima.

sábado, 10 de abril de 2010

Automatizando IMPORT de Bases

Olá Pessoal!

No primeiro post que fiz em Abril/2010, comentei sobre a implementação de um processo "automatizado" de IMPORT de bases de dados. Porém, não detalhei o processo.

Então, para dividir o conhecimento com vocês, resolvi descrever em detalhes o processo.

A receita é simples. Basicamente, consiste das seguintes tarefas:

  1. Bloquear a conta do usuário/esquema;
  2. Desconectar sessões ativas/inativas do usuário;
  3. Dropar o usuário;
  4. Importar os dados.

Detalhando:

Lembrando que, o processo foi desenvolvido utilizando comandos do sistema operacional Windows e scripts para serem executados via SQLPLUS (DBA que é DBA utiliza SQLPLUS ... hehehe).

- Bloquear a conta do usuário a ser carregado E desconectar sessões ativas/inativas do usuário: neste script juntei as atividades de bloqueio da conta do usuário e montagem dinâmica dos KILL SESSIONs das sessões do usuário no BD. O usuário deve ser bloqueado de maneira a evitar novas conexões e suas sessões derrubadas para poder ser dropado. Segue abaixo, um modelo deste script. O script gera log de todas as operações executadas sobre o banco. Aliás, nunca devemos esquecer de gerar log de TUDO, absolutamente TUDO que é executado no BD - é uma boa prática, demonstra profissionalismo e ajuda na identificação de possíveis problemas - mesmo que seja em ambiente de homologação. Resumindo, proteja-se SEMPRE.

killsessionUSUARIO.SQL
SET ECHO OFF
SET HEADING OFF
SET FEEDBACK OFF
CONN sys/****@instancia as sysdba
SPOOL c:\cargas_automaticas\killsessionUSUARIO_2.sql

SELECT 'SPOOL c:\cargas_automaticas\killsessionUSUARIO_2.log' FROM DUAL;
SELECT 'ALTER USER USUARIO ACCOUNT LOCK;' FROM DUAL;
SELECT 'alter system kill session '||chr(39)||sid||','||serial#||chr(39)||';' FROM v$session WHERE username='USUARIO';
SELECT 'SPOOL OFF' FROM DUAL;

SPOOL OFF
SET HEADING ON
SET FEEDBACK ON
SET ECHO ON
@c:\cargas_automaticas\killsessionUSUARIO_2.sql
EXIT

- Dropar o usuário: realizada as operações do passo 1 e 2, as etapas seguintes são dropar o usuário e recriá-lo. Também juntei essas operações em um único script. Segue abaixo o modelo do script para estas tarefas.

recria_USUARIO.sql

SET ECHO on

spool c:\cargas_automaticas\recria_USUARIO.log
conn sys/****@instancia as sysdba
drop user USUARIO cascade;
create user USUARIO identified by senha
default tablespace TBS_USUARIO temporary tablespace TBS_TEMP account unlock;
alter user USUARIO quota unlimited on TBS_USUARIO;

grant create session, alter session, create cluster,
create sequence, create synonym, create table, create view, create indextype,
create procedure,create trigger,create type to USUARIO;

SPOOL off
SET ECHO off
EXIT

- Importar os dados para o usuário: concluída toda a preparação do usuário para receber o conteúdo do DUMP o próximo passo é executar a importação propriamente dita. Para executar as atividades automaticamente, desenvolvi um script que executa todos os passos acima citados concluindo com o comando IMPORT. Abaixo, o script final.

import_USUARIO.cmd

ECHO ********************************

ECHO * Importando INSTANCIA.USUARIO
ECHO ********************************
ECHO *
ECHO * Finalizando sessoes de USUARIO ... Aguarde ...
ECHO *
sqlplus /nolog @c:\cargas_automaticas\killsessionUSUARIO.sql
ECHO *
ECHO *
ECHO * Aguardando 10 minutos para que as conexões terminem antes de dropar o usuário
ECHO *
sleep 600
ECHO *
ECHO * Recriando usuario USUARIO ...
ECHO *
sqlplus /nolog @c:\cargas_automaticas\recria_USUARIO.sql
ECHO *
ECHO * Importando base de dados USUARIO ...
ECHO *
imp sys/****@instancia file=c:\cargas_automaticas\arquivo.dmp fromuser=usuario touser=usuario log=c:\cargas_automaticas\import_usuario.cmd recalculate_statistics=Y
ECHO *
ECHO ********************************

Para minimizar os riscos de alguma sessão conectada ao usuário e conseguir eliminar o usuário/esquema, implementei o comando SLEEP do WINDOWS para "congelar' a sessão do sistema operacional durante 10 minutos. Lembrando que, o aplicativo SLEEP.EXE é instalado com o pacote RESOURCE KIT do WINDOWS.

Até a próxima.

terça-feira, 6 de abril de 2010

Melhorando a performance de IMPORT/EXPORT

Olá!

Um dos maiores problemas em ambientes de homologação que  necessitam de grandes volumes de cargas de bases de dados para desenvolvimento e testes de usuários (como no meu caso ...) é a dificuldade em obter performance no EXPORT/IMPORT dos dados de forma a disponibilizá-los o mais rápido possível para desenvolvedores e usuários. No decorrer dos anos, com a constante necessidade de carregar tais bases com aquele velho papo de "pra ontem", fui observando alguns ítens que melhoram a performance destas operações.

Vale lembrar que, se você não possue um hardware com uma configuração mínima aceitável, a utilização de determinados parâmetros de IMPORT/EXPORT não terá impactos sobre estas operações.

Abaixo, listei algumas dicas e espero que sejam úteis:

- IMPORT

  1. Desabilite a importação de índices: se for possível, desabilite a importação de índices configurando o parâmetro INDEXES=N. Na maioria dos casos, desenvolvedores e usuários, estão interessados nos dados. Desta forma, se você tem uma boa ferramenta como o SQL Developer da Oracle, pode gerar um script que executa a criação dos índices após a carga. Enquanto isso, os dados podem ser acessados durante este processo agilizando a identificação de um problema;
  2. Elimine a carga de grandes tabelas durante a importação: na maioria dos casos, bases de desenvolvimento/homologação não necessitam de todas as tabelas da aplicação. Neste caso, evite a carga de tabelas maiores desnecessárias durante o IMPORT. Como? Crie a estrutura de tais tabelas antes da carga e utilize o parâmetro IGNORE=N (lembrando que esta é valor padrão do parâmetro) no import. Isto fará com que o IMPORT gere erro IMP-00015: following statement failed because the object already exists e "saltará" a importação dessas tabelas. Dependendo do tamanho da tabela, o ganho de tempo pode ser significativo;
  3. Crie processos de importações automáticas de bases em horários de baixo load do BD: normalmente, os desenvolvimentos/homologações de aplicações são feitos durante o horário normal de trabalho (8h às 18h), salvo em casos específicos onde exista uma necessidade urgente de homologação o que também é raro em qualquer empresa com bom planejamento e organização de seus processos. Uma boa prática é criar processos de carga, através de scripts e jobs do WINDOWS ou do próprio ORACLE para realizar automaticamente estes trabalhos. Obviamente, os jobs devem ser agendados para os horários de menor load do banco. Uma boa sugestão de horário é durante a madrugada, pois raramente se trabalha neste horário. A não ser que você seja um DBA ... hehehe ... brincadeira gente ... Se o fluxo de homologações e demanda por bases de dados é muito alto, vale a pena investir tempo na implementação de um processo com esta finalidade;
  4. Aumente o tamanho dos arquivos de redolog e parâmetros de sort: por se tratar de uma operação com características de processos BATCH, o aumento de tamanho dos redologs e dos parâmetros de SORT (sort_area_size e sort_area_retained_size) podem dar um plus na performance do IMPORT. Já tive ganhos consideráveis utilizando o padrão 10 grupos de redologs com tamanho de 100Mb cada. Mas é claro, você tem que adequar a configuração de acordo com o seu BD. Para parâmetros de SORT, utilize valores maiores. Uma configuração razoável é 2Mb para os 2;
  5. Evite operações de IMPORT/EXPORT no modo shared server: utilize SEMPRE conexões dedicadas para tais operações.

- EXPORT

Para estas operações, são poucas as dicas:

  1. Utilize o parâmetro DIRECT=Y: isto faz com que o ORACLE ultrapasse a camada de processamento de comandos SQL. Isto reduz bastante o tempo do EXPORT;
  2. Evite o parâmetro FEEDBACK: a configuração deste parâmetro, exige consumo de processamento da máquina para exibição dos resultados em tela.

Pessoal, essas são algumas dicas que achei interessante compartilhar com vocês. Espero que as utilizem em alguma eventual necessidade.

Até a próxima.