Arquivo da categoria: automatizar tarefas.

Oracle 11G IMPDP – TRANSFORM – Caso Compress

Olá PessoAll,

Não sei se todos conheciam isso, eu particularmente nunca tinha usado, resolvi compartilhar.

Eu precisava fazer um import de um owner que atualmente está em tablespace normal, e tem suas tabelas normais para que ele fosse importado em uma outra tablespace e já comprimido (COMPRESS).

Fiz o export normalmente, sem nenhum segredo. Na hora do import que seriam realizadas as mudanças.

No import, a primeira coisa é que eu precisava era colocar as tabelas e índices numa nova tablespace. Para isso, usei o REMAP_TABLESPACE, até aí sem nenhum segredo.

Porém, como faria para que as tabelas fossem criadas comprimidas?

O atributo de COMPRESS, geralmente usado nas tabelas não tinha como ser mudado na hora do import.

As alternativas eram:

1 – Importar assim mesmo e fazer um Redefinition depois.

2 – Fazer o import com METADATA_ONLY e mudar as tabelas para COMPRESS, só que desse jeito os índices vão junto e na hora do import com os dados (DATA_ONLY) vai demora muito mais, estoura UNDO etc.

3 – Gerar o script de criação das tabelas, uma por uma, e criar manualmente apenas a tabela na nova tablespace e com COMPRESS e só depois soltar o IMPDP.

 

Baseado nas possibilidades pensadas… A alternativa mais interessante e que resolvia era a 3, mas ia dar um trabalho enorme…. uma a uma, criar na mão…. muito trabalho!

Um dos dons (se bem usado) do ser humano é a “preguiça produtiva”, e usei deste dom… em vez de fazer assim, saí pesquisando.

Nas buscas, descobri então que o atributo de COMPRESS pode ser como default na tablespace… Aí sim… só criar a tablespace e informar a cláusula: “…default compress for oltp”, e toda tabela criada na tablespace que não informar nada sobre compressão, será assumida a compressão da tablespace! Aêêêê!!! Resolveu!  \o/

Só que não!

Fiz o import, e ao verificar as tabelas, todas estavam sem compressão! Mesmo a tablespace estando com o default COMPRESSION FOR OLTP.

Dica: Se você tem dúvida de como verifica isso na tabela, assim é possível: select table_name, compression, compress_for from dba_tables where owner='SEU_OWNER_AQUI'

Quebrou meu esquema!

Lá vem a preguiça voltando novamente e lá vou eu pesquisar novamente.

Gastei mais um tempo de pesquisa e descobri o porquê das tabelas não obedecerem ao default da tablespace, lembram quando falei lá em cima: “e toda tabela criada na tablespace que não informar nada sobre compressão”, pois é…. SE não informar nada! Só que quando o expdp é feito, o script gerado de criação da tabela vem com o atributo NOCOMPRESS, porque no banco de origem a tabela de fato não era comprimida, na hora do import a tabela era criada com o atributo original contido no script, NOCOMPRESS!

Voltamos então para a solução 3, gerando o script dos create table, mudando o script de cada uma das tabelas e criando todas as tabelas manualmente, com COMPRESS… mas minha preguiça produtiva é resistente e resiliente… pesquisei mais um pouco, para fazer de forma mais inteligente… e achei o tal atributo TRANSFORM do IMPDP!

Vamos lá… no IMPDP, com o TRANSFORM, você pode exatamente mudar atributos dos objetos a serem criados na hora do IMPDP, ficando diferente do que foi gerado no banco de origem.

Para o meu caso, eu precisava apenas remover o tal NOCOMPRESS do script de criação, e dizer para o banco que as tabelas deveriam ir para uma tablespace nova, isso é possível adicionando as seguintes clausulas, combinadas, no meu comando de IMPDP:

...transform=segment_attributes:n remap_tablespace=TBS_OLD:TBS_NEW_COMPRESS...

Desta forma, os atributos do segmento que estavam no banco antigo (e no script do IMPDP) não serão utilizados, fazendo com que o default da nova tablespace seja usado.

E a preguiça vence novamente!! Tabelas criadas com COMPRESS FOR OLTP e import rolando.

Espero que seja útil para vocês.

Podemos usar isso, por exemplo, nos refresh de bases que fazemos com EXPDP/IMPDP, devemos economizar uma área razoável nas bases de desenvolvimento e homologação com esse método.

É uma ideia!

As notas que encontrei nas pesquisas foram:

Internet:

http://www.dba-oracle.com/t_impdp_transform_segment_attributes.htm

https://docs.oracle.com/cd/E11882_01/server.112/e22490/dp_import.htm#SUTIL939

Metalink:

How To Import The Non-Compressed Tables Into A Compressed Tablespace And Obtain Compress Target Tables? (Doc ID 2174751.1)

E….. só para constar, vi que no 12c, tem muito mais atributos que poderão ser usados com o TRANSFORM, como pode exemplo, não precisar ter default da tablespace, no próprio comando de IMPDP poderemos substituir o valor dos parâmetros, por exemplo, trocar o NOCOMPRESS por COMPRESS FOR OLTP, vejam mais detalhes aqui:

https://docs.oracle.com/database/121/SUTIL/GUID-64FB67BD-EB67-4F50-A4D2-5D34518E6BDB.htm#SUTIL939

 

É isso gente.

Espero ter ajudado!

 

Abraços!

Dica de SQL – Primeiro sábado do mês seguinte

Fala PessoAll,

Recebi um email do amigo Vitor Ugo sobre uma solicitação que ele havia recebido para criação de um Job.

Até aí moleza, como podemos ver no post: Job no Oracle criar um Job é fácil! Só que este Job tem uma particularidade, ele deve rodar apenas no primeiro sábado de cada mês.

Com isso, fiz a dica para Vitor, dele colocar o job para executar todo dia, e antes de chamar a procedure do job fazer um teste e identificar se era o primeiro sábado, se sim, beleza roda a procedure, senão, não faz nada! Funcionaria, porém não é uma solução das mais bonitas, porque mesmo sem fazer nada, o job executaria todos os dias.

Foi então que o Vitor desenvolveu um select, que recupera o primeiro sábado do mês seguinte, e resolveu todos os problemas.

Segue o select desenvolvido por Vitor:


select LEAST(NEXT_DAY(ADD_MONTHS(trunc(sysdate,'MM')+(8/24),1)-1,7),
next_day(ADD_MONTHS(trunc(sysdate,'MM')+(8/24),1),7)) from dual;

Neste select o “7” indica que é um sábado, caso desejem outro dia da semana, basta que vocês alterem esse número para o dia desejado!

É isso, fica aí a dica. Espero que gostem

Abraço a todos.

Atc.
Gerson Júnior
gerson.vasconcelos@gmail.com

Job não executa no Oracle 8i (DBA)

Fala PessoALL,

Bom, ontem me deparei com mais um pequeno probleminha…
Criei um Job em um banco de dados Oracle 8i, o job estava criado certinho, com as datas de Next_Sec setadas, ou seja, tudo perfeito pra rodar. Pra confirmar se a procedure do Job estava ok, executei manualmente o Job, pra ver se seria alimentado o campo Failures, ou se manteria 0 (zero).

Executei manualmente assim:

begin
dbms_job.run(1);
end;

Depois conferi e Failures permanecia 0 (zero), perfeito. Era só esperar a próxima hora de execução (Next_Sec) e ele rodaria perfeitamente! No horário esperado… cadê??? Nada do Job executar!

Aí vamos as pesquisas… recorri ao grupo GPOracle e aí me veio a dica: “Dá uma olhada no parâmetro JOB_QUEUE_PROCESSES“.

Então vamos lá, olhar o parâmetro:


SQL> select name, value from v$parameter where name like '%job_queue%';

NAME VALUE
--------------------- ------------------
job_queue_processes 0

Hum… está como 0 (zero), ou seja, estou dizendo pro banco que nenhum processo de Job vai rodar na minha base.

Beleza, então vamos alterar este parâmetro.

Supondo que você está conectado com um usuário com tal privilégio…


SQL> alter system set job_queue_processes=10;

Sistema alterado.

SQL> select name, value from v$parameter where name like '%job_queue%';

NAME VALUE
--------------------- ------------------
job_queue_processes 10

Pronto! Como este parâmetro é dinâmico, seu banco já está ok! Seus Job’s já vão funcionar normalmente.

Lembrando que para que a alteração se mantenha em um possível shutdown -> startup no seu banco, é necessário que no arquivo initBASE.ora deve ser adicionada a linha job_queue_processes=10 para que na inicialização este parâmetro seja devidamente carregado.

É isso gente, espero que seja útil pra vocês!!

Atc.
Gerson Júnior
gerson.vasconcelos@gmail.com

JOB no ORACLE – Definindo a periodicidade. (INTERVAL)

Fala PessoALL,

Bom, atendendo à dica do amigo Alessandro Varela (http://blogdovarela.com.br) hoje falarei sobre: Como definir corretamente a periodicidade da execução dos seus Job’s! Complica não? É nada!! Vamos lá!

Espero que todos tenham lido o post que fiz falando sobre Job’s, caso não tenha lido, ainda dá tempo, basta ler o post Jobs no Oracle.

Bom, quando fazemos a criação de um Job, é porque temos a necessidade que uma determinada tarefa seja executada de tempos em tempos, e para isso geralmente precisamos definir um intervalo para que o Job seja executado novamente. Por exemplo: Quero que meu Job rode a cada hora, quero que meu Job rode todo dia de 23:00, quero que meu job rode a cada 5 minutos, e assim por diante. Só que no momento de fazer esta parametrização é quando começa a confusão, pois, as pessoas esquecem de que o Job vai rodar sozinho e ele é quem tem que definir a próxma execução! Para simplificar isso, vamos lá!

Todo mundo lembra no post anterior que eu falei que para criar um Job usamos a package DBMS_JOB e a procedure DBMS_JOB.SUBMIT(...), certo? Pois é, nesta procedure, um dos parâmetros que é passado é um tal de INTERVAL, ou seja, o intervalo entre cada execução do seu Job. É aqui que mora o X (xis) da questão! É neste parametro que vamos informar de quanto em quando tempo nosso Job vai rodar.

O que tem que ser considerado aqui, é que o Job será executado automaticamente (essa é a razão do seu existir) e é justamente por isso que rola a confusão, quando este parâmetro for usado já não estaremos mais na data “agora”, estaremos na data de execução do Job, sei lá, 23:00! E aí o banco vai usar este parâmetro INTERVAL para setar o campo NEXT_DATE, que é a próxima data em que o Job será executado, ou seja você tem que levar em consideração que o banco sempre vai usar sysdate para calcular este valor.

Como é de rotina, vamos para os exemplos que tudo vai ficar mais claro.
Exemplos mais comuns:

Job para rodar de hora em hora:
Interval -> ‘sysdate + 1/24’
Ou seja, se este Job rodar dia 25/10/2009 às 14:00, quando for somada 1 hora, teremos 15:00 como NEXT_DATE.

Job para rodar a cada 5 minutos.
Interval -> ‘sysdate + 5/1440’
Ou seja, se este Job rodar dia 25/10/2009 às 14:00, quando for somado 5 minutos (1/1440), teremos 14:05 como NEXT_DATE.

Job para rodar uma vez por mês:
Interval -> ‘add_months(sysdate, 1)’
Ou seja, se executar dia 25/10/2009, aplicando este valor acima, teriamos 25/11/2009 como NEXT_DATE.

Esse foi um dos casos mais estranhos, pedido através do blog pra mim…
Job para rodar em um dia específico a cada ano e numa determinada hora:
‘add_months(to_date(to_char(sysdate, ”DD/MM/YYYY”)||” 05:00”, ”DD/MM/YYYY HH24:MI”), 12)’
Ou seja, se o job rodar dia 25/10/2009 as 15:00, e aplicarmos esta fórmula aí, teremos 25/10/2010 05:00 como NEXT_DATE.

Uma dica legal para você fazer esta fórmula que será o NEXT_DATE do seu Job é dar select em sysdate usando a dual. Que eu creio ser o que o banco faz na hora de rodar o Job.

Por exemplo:
Se executarmos o comando:
select sysdate, sysdate + 1/24 from dual
Vamos obter como retorno:

sysdate sysdate + 1/24
20/10/2009 15:55:35 20/10/2009 16:55:35

Isso aí nos dá a hora atual e a hora atual somado 1 hora. Assim você monta seu NEXT_DATE facilmente!

É isso pessoal, espero que tenha ficado claro e que daqui pra frente seja mais fácil montar seus Jobs para as mais diversas necesidades.

Qualquer coisa, estamos por aqui!

Atc.
Gerson Júnior
gerson.vasconcelos@gmail.com

Job no Oracle

Fala PessoALL,

Atendendo a pedidos, hoje falaremos sobre Job’s no Oracle.
Do que se trata? Job’s são tarefas que são “scheduladas” (agendadas) no Oracle para rodar numa determinada hora que você estipula.

Como assim? Bom, vamos aos exemplos:

Suponha que você tem um sistema na sua empresa de controle de acesso, ele é quem gera os crachás para os funcionários entrarem na empresa. No sistema de RH, é onde são cadastrados os meus funcionários… e agora? Tenho que fazer os dois sistemas conversarem. Geralmente essa “conversa” é feita através de arquivos, chamados EDI (eletronic Data Interchange) e seu sistema de RH teria que gerar esses arquivos diariamente durante a noite com todas as pessoas Admitidas e Demitidas para que o sistema de crachá leia este arquivo e habilite ou desabilite o acesso do funcionário. Como fazer?

Criamos um JOB para gerar este arquivo “na calada da noite”.

Num JOB você diz as rotinas que vão ser executadas, que podem ser códigos direto com blocos de PL/SQL, ou podem ser chamadas Procedures ou Packages que executam as rotinas que você precisa.

Suponhamos mais uma vez, que neste nosso exemplo, precisamos de um JOB que chame a procedure: Pr_Gera_Arq_Mov_Funcionarios, e este JOB precisa gerar este arquivo às 22:00, porque às 23:00 o sistema de controle de acesso vai ler o arquivo gerado. Pronto… cenário montado, vamos criar o JOB.

Como criamos um JOB? Temos no banco de dados Oracle uma Package que faz todo controle e manipulação dos JOB’s no banco, o nome dela é DBMS_JOB, e é ela que vamos utilizar para criar nosso JOB. Como fazemos isso? Com blocos de PL/SQL, simples e rápido, assim:


declare
--Declare variável que recebe número do JOB.
job_num binary_integer;
begin
--Cria o JOB no banco e retorna o número dele job_num
dbms_job.submit(job_num,
'begin Pr_Gera_Arq_Mov_Funcionarios; end;',
to_date('10/06/2009, 22:00', 'dd/mm/yyyy hh24:mi'),
'sysdate + 1');
end;

Vamos explicar….

A rotina dbms_job.submit(...) exige 2 parâmetros como obrigatórios, são eles:
job, que é um parâmetro OUT, ou seja, a rotina vai retornar um valor para a variável que estiver neste local, no nosso caso é o número do JOB.
what que é uma string que diz para o banco que rotinas o JOB vai executar, note que este parâmetro é uma string e tem que conter um bloco PL/SQL, ou seja, tem que ter begin...end; e tudo mais.

Os outros dois parâmetros passados neste caso, para a rotina dbms_job.submit(...) não são obrigatórios, eles são responsáveis por dizer que data o JOB vai rodar a próxima vez (next_date) e com que intervalo vai rodar novamente (interval), não são obrigatórios porque na package dbms_job existe diversas outras procedures que manipulam os JOB’s e entre elas está dbms_job.next_date(...) e dbms_job.interval(...) (entre outras), nestas rotinas é necessário informar o número do JOB e o valor que você deseja atribuir para estes atributos.

Observe que o tempo todo falamos de “número do JOB”, é isso mesmo. No Oracle, os JOB’s são identificados por números, não tem como atribuirmos nomes aos JOB’s (nem tudo é perfeito), por isso, na rotina que cria o JOB ele exige uma variável para receber o número que foi atribuído ao JOB.

Depois do seu JOB criado, você pode fazer alterações no bloco que o JOB executa, na próxima vez que ele vai rodar, no intervalo e etc, tudo usando as procedures da package dbms_job.

Para listar os JOB’s criados no seu banco de dados, bem como ver os seus Status, ultimas execuções, Status de execução, Próxima vez que vai rodar e etc, podemos dar um select na view user_jobs. E se ainda, quisermos saber que JOB’s estão sendo executados neste exato momento, podemos dar um select na tabela dba_jobs_running, mas para esta segunda você precisa ter privilégios de DBA.

Espero ter sido claro e tomara que este post seja útil.
Qualquer dúvida não deixe de enviar um comentário ou até mesmo e-mail que descobrimos juntos as respostas.

Abraços à todos.

Atc.
Gerson Júnior
gerson.vasconcelos@gmail.com