PGDay RS no dia 19 de agosto de 2011
15 de Agosto de 2011, 0:00 - sem comentários aindaO pessoal de RS se mexeu e mais um PGDay RS estará ocorrendo este ano. Será no dia 19 de agosto (sexta-feira) em Porto Alegre.
Os palestrantes, a programação e o local estão todos publicados no site do evento. Infelizmente não vou poder estar lá, mas já vi que a grade de palestrantes é excelente e será um evento bem bacana, incluindo um Dojo PL/pgSQL e os já conhecidos Lightning Talks.
Gostaria aqui de parabenizar os palestrantes Dickson Guedes, Diego Rossi, Diogo Biazus, Eduardo Wolak e Fabiano Machado Dias por palestrarem no evento e em especial para o Fabrízio de Royes Mello que é a pessoa que está liderando a organização do evento.
Não esqueçam de mandarem as fotos, publicarem as palestas, ok?
PGBR2011 – Chamada de trabalhos
14 de Agosto de 2011, 0:00 - sem comentários aindaNesta semana foi aberta a Chamada de Trabalhos do PGBR2011.
A chamada ficará aberta até o dia 09/09/2011 então não bobeie e mande logo as suas propostas. Este ano serão 4 modalidades diferentes (fora os Lightning Talks): Palestras normais de 50 minutos, tutoriais de 2 horas, hacker talks que podem der de 30 minutos até 2 horas e os painéis acadêmicos que serão expostos no saguão do evento. Tudo explicado no site do evento. Você pode mandar até 5 propostas diferentes para a banca avaliadora (da qual eu não faço parte) escolher.
Eu já estou preparando as minhas propostas, mas segue algumas que eu gostaria de ver lá. Eu sei que tem muita gente que já usa PostgreSQL há um tempão e acha que não teria nada de interessante para falar. Não se intimide, tenho certeza que se você usa o PostgreSQL há mais de um ano, deve se sentir à vontade para falar algum assunto como:
-
Postgressssss, lendas urbanas sobre PostgreSQL e um apanhado da sua evolução nas últimas versões;
-
Casos de sucesso de quem não tem vergonha de revelar que usa o PostgreSQL em negócios críticos;
-
Porquê o PostgreSQL é cada vez mais amante predileta dos DBAs experientes;
-
“Meu PostgreSQL não Conecta” e outras coisas que alguém tem de escrever para a gente não repetir novamente na lista…
-
Ops, minha base já tem mais de 1TB… ;
-
BI, Data Mining, OLAP, PL/R e outros bichos;
-
Full Text Search, particularmente como raios se montam Ranks e dicionários personalizados;
-
Funções de agregação personalizadas, operadores personalizados, tipos de dados personalizados e o que mais você tiver coragem de inventar;
-
Bancos de dados em pesquisas científicas, como em biologia, física e outras ciências ocultas;
-
Haks, muitos hacks! Queremos hacks em C, em Perl, Python, SPI, PL/pgSQL etc. Queremos nerds genuínos!!!
-
Vou te apresentar a uma tal de libpq…
-
Tuning em bases OLTP com fuking hight concorrência;
-
ETL (Extract Transform Load) em ambientes alucinógenos;
-
pgbench e outras técnicas para emular a carga da aplicação em ambiente de homologação ou “hum…. então dá para fazer isso antes de sentar a aplicação no cliente?”
-
Versionamento DDL e como controlar do demônio da tasmânia das alterações de estrutura entra desenvolvimento e produção sem ir parar no hospital;
-
Segurem os trolls, vamos falar sobre sistemas de arquivos, tablespaces e discos de novo….
-
Como fazer poesia com SQL e parar de fazer caquinha com PL/você_não_precisa_usar_isto_aqui.
-
Técnicas (ok, se você gosta de buzzwords, pode chamar de “design patterns”) de otimização de processos e ajuste de SQL em PostgreSQL;
-
“Rodei o EXPLAIN, e agora?”;
-
Magia negra com Window Function;
-
CTE, recursividade e como não destruir a memória do seu servidor;
-
Localização, codificação de caracteres e coisas que infelizmente você tem de aprender se não quiser sofrer por toda a eternamente com isso;
-
Segurança para preguiçosos (ou seja, para todo mundo…);
-
Técnicas de monitoramento, administração que funcionam e fazem sentido para seres mortais;
-
Armadilhas no zoológico das replicações;
-
Muito além das configurações do postgresql.conf: personalizando bases, roles , tabelas, tablespaces e até sessões para um ajuste perfeito;
-
Eu sei, eu sei…. ACID, blá, blá, blá, Teoria Relacional, etc e tal, mas o C. J. Date diz que bi, bi, bi, bó, bó, bó…. mas eu quero muito ver “Técnicas de NoSQL integradas com PosgreSQL”;
-
Backup e o “complexo de Chuck Norris”. (Quem respondeu a pesquisa sobre uso de PostgreSQL sabe do que eu estou falando);
-
Técnicas de recuperação de desastres e como é chato ouvir “mas eu já faço assim há 5 anos e nunca deu nenhum problema…”;
-
Não entendeu? Vou falar de novo: RECOVER, RECOVER, RECOVER!
-
Quer dizer então que para ter um banco de dados é preciso ter um DBA na equipe ou aprender como fazer o trabalho de um?
OBS: Quem sabe este ano o indefectível Osvaldo Kussama não manda uma proposta?
OBS2: Se tiver alguma outra sugestão de palestra que você gostaria de ver no PGBR201, não deixe de deixar um comentário aqui! Vai que alguém gosta da ideia e você acaba tendo uma aula sobre aquele tema que vem lhe assombrando há tempos…
PGBR2011 – Chamada de trabalhos
14 de Agosto de 2011, 0:00 - sem comentários aindaNesta semana foi aberta a Chamada de Trabalhos do PGBR2011.
A chamada ficará aberta até o dia 09/09/2011 então não bobeie e mande logo as suas propostas. Este ano serão 4 modalidades diferentes (fora os Lightning Talks): Palestras normais de 50 minutos, tutoriais de 2 horas, hacker talks que podem der de 30 minutos até 2 horas e os painéis acadêmicos que serão expostos no saguão do evento. Tudo explicado no site do evento. Você pode mandar até 5 propostas diferentes para a banca avaliadora (da qual eu não faço parte) escolher.
Eu já estou preparando as minhas propostas, mas segue algumas que eu gostaria de ver lá. Eu sei que tem muita gente que já usa PostgreSQL há um tempão e acha que não teria nada de interessante para falar. Não se intimide, tenho certeza que se você usa o PostgreSQL há mais de um ano, deve se sentir à vontade para falar algum assunto como:
-
Postgressssss, lendas urbanas sobre PostgreSQL e um apanhado da sua evolução nas últimas versões;
-
Casos de sucesso de quem não tem vergonha de revelar que usa o PostgreSQL em negócios críticos;
-
Porquê o PostgreSQL é cada vez mais amante predileta dos DBAs experientes;
-
“Meu PostgreSQL não Conecta” e outras coisas que alguém tem de escrever para a gente não repetir novamente na lista…
-
Ops, minha base já tem mais de 1TB… ;
-
BI, Data Mining, OLAP, PL/R e outros bichos;
-
Full Text Search, particularmente como raios se montam Ranks e dicionários personalizados;
-
Funções de agregação personalizadas, operadores personalizados, tipos de dados personalizados e o que mais você tiver coragem de inventar;
-
Bancos de dados em pesquisas científicas, como em biologia, física e outras ciências ocultas;
-
Haks, muitos hacks! Queremos hacks em C, em Perl, Python, SPI, PL/pgSQL etc. Queremos nerds genuínos!!!
-
Vou te apresentar a uma tal de libpq…
-
Tuning em bases OLTP com fuking hight concorrência;
-
ETL (Extract Transform Load) em ambientes alucinógenos;
-
pgbench e outras técnicas para emular a carga da aplicação em ambiente de homologação ou “hum…. então dá para fazer isso antes de sentar a aplicação no cliente?”
-
Versionamento DDL e como controlar do demônio da tasmânia das alterações de estrutura entra desenvolvimento e produção sem ir parar no hospital;
-
Segurem os trolls, vamos falar sobre sistemas de arquivos, tablespaces e discos de novo….
-
Como fazer poesia com SQL e parar de fazer caquinha com PL/você_não_precisa_usar_isto_aqui.
-
Técnicas (ok, se você gosta de buzzwords, pode chamar de “design patterns”) de otimização de processos e ajuste de SQL em PostgreSQL;
-
“Rodei o EXPLAIN, e agora?”;
-
Magia negra com Window Function;
-
CTE, recursividade e como não destruir a memória do seu servidor;
-
Localização, codificação de caracteres e coisas que infelizmente você tem de aprender se não quiser sofrer por toda a eternamente com isso;
-
Segurança para preguiçosos (ou seja, para todo mundo…);
-
Técnicas de monitoramento, administração que funcionam e fazem sentido para seres mortais;
-
Armadilhas no zoológico das replicações;
-
Muito além das configurações do postgresql.conf: personalizando bases, roles , tabelas, tablespaces e até sessões para um ajuste perfeito;
-
Eu sei, eu sei…. ACID, blá, blá, blá, Teoria Relacional, etc e tal, mas o C. J. Date diz que bi, bi, bi, bó, bó, bó…. mas eu quero muito ver “Técnicas de NoSQL integradas com PosgreSQL”;
-
Backup e o “complexo de Chuck Norris”. (Quem respondeu a pesquisa sobre uso de PostgreSQL sabe do que eu estou falando);
-
Técnicas de recuperação de desastres e como é chato ouvir “mas eu já faço assim há 5 anos e nunca deu nenhum problema…”;
-
Não entendeu? Vou falar de novo: RECOVER, RECOVER, RECOVER!
-
Quer dizer então que para ter um banco de dados é preciso ter um DBA na equipe ou aprender como fazer o trabalho de um?
OBS: Quem sabe este ano o indefectível Osvaldo Kussama não manda uma proposta?
OBS2: Se tiver alguma outra sugestão de palestra que você gostaria de ver no PGBR201, não deixe de deixar um comentário aqui! Vai que alguém gosta da ideia e você acaba tendo uma aula sobre aquele tema que vem lhe assombrando há tempos…
Arrumando a ordem das colunas em índices compostos
27 de Junho de 2011, 0:00 - sem comentários aindaO título é grande mas eu vou tentar explicar da forma mais rápida possível. Na verdade o caso não é tão simples assim…. vejamos:
O problema
- É comum você precisar criar índices com várias colunas ao mesmo tempo. Em chaves naturais isso ocorre com frequência e é quase obrigatório em relações de “N para N”, quando uma tabela intermediária recebe como chave primária (vou abreviar aqui como PK, ou Primary Key) as chaves de duas tabelas, como a famosa tabela “detalhes_pedido” com as chaves da tabela “pedido” e “produto”.
- A ordem dos tratores altera completamente o viaduto. Se você tem as colunas A, B e C num índice composto, você tem de criar o índice com numa ordem específica: da coluna com menor variação de dados, para a coluna com maior variação de dados.
- Vamos entender que variação aqui, é a quantidade de valores diferentes que uma coluna pode assumir em relação ao número de registros da tabela. Uma coluna que sozinha responde pela PK tem 100% de variação, pois todos os registros tem valores distintos. Uma tabela que possui apenas 2 valores distintos numa tabela com milhares de registros, tem 50% de variação.
- No catálogo do PostgreSQL (o PG_CATALOG), temos 2 lugares que mostram a variação de uma coluna: pg_statistics e a visão sobre esta tabela que é a pg_stats . Estas tabelas são alimentadas pela rotina de VACUUM ANALYZE.
- Índices criados com uma ordem errada, onde colunas com variação baixa são colocadas no final do comando CREATE INDEX ou na definição de uma PK ou UK (que criam índices implícitos com na mesma ordem da restrição PK ou UK) vão resultar num índice ineficiente. Esta ineficiência se traduz em desperdício de espaço em disco, maior sentidão no processo de INDEX SCAN e há terríveis casos onde uma consulta com um filtro (leia-se WHERE) num dos campos do índice não vai conseguir utilizar aquele índice.
- Este problema não é uma particularidade do PostgreSQL, ele ocorre nos demais SGDBs também. Infelizmente a maneira de detectar o problema é diferente em cada um, pois o acesso à este tipo de informação não está presente no Information Schema, que faz parte do padrão SQL;
- Na tabela pg_statistic a coluna ‘stadistinct’ que equivale à coluna n_distinct na visão pg_stats. O significado da coluna não é tão trivial. Vejamos:
- Se o valor for 0 (zero), então significa que não foi coletada nenhuma informação no ANALYZE. Rode esta rotina e depois verifique novamente;
- Se o valor for positivo, então ele indica o número de valores diferentes que a coluna recebe. O valor positivo também significa que ao rodar o ANALYZE, o PostgreSQL acredita (ele pode errar) que o número de valores é fixo, ou seja, são sempre os mesmos valores nas colunas, independente do número de registros.
- Se o valor for negativo, então você tem o número de valores distintos naquela coluna já dividido pelo número de registros da tabela.
Verificando as estatísticas de um único índice
Bom, então eu criei uma consulta para verificar como estão as estatísticas de cada coluna de um índice específico:
SELECT n.nspname AS "Schema", c2.relname AS "Table", c.relname AS "Index", TO_CHAR(c.reltuples,'999G999G999') AS num_rows, c.relnatts AS col_count, a.attnum AS Ord, a.attname AS "Column", TO_CHAR(CASE WHEN s.n_distinct = 0 THEN 0 WHEN s.n_distinct < 0 THEN @ 100 * s.n_distinct WHEN s.n_distinct > 0 THEN 100 * s.n_distinct / c2.reltuples END ,'000D99') AS "%Var", format_type(a.atttypid, a.atttypmod) AS "Type" FROM pg_class AS c JOIN pg_namespace AS n ON n.oid = c.relnamespace JOIN pg_index AS i ON c.oid = i.indexrelid JOIN pg_class AS c2 ON c2.oid = indrelid JOIN pg_attribute AS a ON a.attrelid = i.indexrelid JOIN pg_stats AS s ON s.tablename = c2.relname AND s.attname = a.attname WHERE n.nspname NOT IN ('pg_catalog','information_schema') AND a.attnum > 0 AND NOT a.attisdropped AND c.relnatts > 0 AND c.relname = 'nome_do_índice' ORDER BY a.attnum;
Vejamos como esta consulta fica com o índice film_actor_pkey da base PAGILA:
Schema | Table | Index | num_rows | col_count | ord | Column | %Var | Type -------+------------+-----------------+--------------+-----------+-----+----------+---------+---------- public | film_actor | film_actor_pkey | 5.462 | 2 | 1 | actor_id | 003,66 | smallint public | film_actor | film_actor_pkey | 5.462 | 2 | 2 | film_id | 018,25 | smallint
Aqui notamos que o índice está OK, pois a 1ª coluna tem ~3,7% de variação e a 2ª tem ~18%.
Verificando todos índices com ordem trocada na base
O problema é que eu queria verificar todos os índices (tirando os índices do próprio catálogo) que possuem índices onde a ordem está invertida. Então eu montei a consulta abaixo para me ajudar:
WITH multi_col AS (SELECT i.indexrelid AS index_oid, n.nspname AS schema, c2.relname AS TABLE, c2.reltuples AS row_num, c.relname AS INDEX, a.attnum AS n_col, a.attname AS col, CASE WHEN s.n_distinct = 0 THEN 0 WHEN s.n_distinct < 0 THEN @ s.n_distinct WHEN s.n_distinct > 0 THEN s.n_distinct / c2.reltuples END AS var FROM pg_class AS c JOIN pg_namespace AS n ON n.oid = c.relnamespace JOIN pg_index AS i ON c.oid = i.indexrelid JOIN pg_class AS c2 ON c2.oid = indrelid JOIN pg_attribute AS a ON a.attrelid = i.indexrelid JOIN pg_stats AS s ON s.tablename = c2.relname AND s.attname = a.attname WHERE n.nspname NOT IN ('pg_catalog','information_schema') AND a.attnum > 0 AND NOT a.attisdropped AND c.relnatts > 1 ), wrong_col AS (SELECT col_a.index_oid, col_a.col FROM multi_col AS col_a JOIN multi_col AS col_b ON col_a.index_oid = col_b.index_oid AND col_a.n_col = col_b.n_col + 1 AND col_a.var < col_b.var) SELECT DISTINCT col.schema, col.TABLE, col.INDEX, TO_CHAR(col.row_num,'999G999G999'), col.n_col, col.col || CASE wrong_ind_col.col WHEN col.col THEN ' ***' ELSE '' END AS col, TO_CHAR(col.var,'0D99999') AS var, pg_get_indexdef(col.index_oid) AS "CREATE" FROM multi_col AS col JOIN wrong_col AS wrong_index ON col.index_oid = wrong_index.index_oid LEFT JOIN wrong_col AS wrong_ind_col ON col.index_oid = wrong_ind_col.index_oid AND col.col = wrong_ind_col.col WHERE row_num > 1000 ORDER BY col.schema, col.TABLE, col.INDEX, col.n_col;
Observações
- Esta consulta utiliza um pouco de CTE para facilitar, portanto só funciona a partir do PostgreSQL 8.4.
- Cuidado!!! Estas consultas não fazem o menor sentido se o ANALYZE não estiver atualizado e se você não está utilizando dados reais na sua base. Se você tem uma base de testes com dados fictícios, então você tem de confiar na sua capacidade de modelagem quando você prevê qual coluna tem variação maior.
- Eu coloquei no meio desta consulta um filtro para pegar apenas os índices de tabelas com mais de mil registros. Índices de tabelas com poucos registros não são utilizados de qualquer forma numa consulta, então eu resolvi ignora-las.
De qualquer forma, a consulta é uma ferramenta para ajudar o DBA a detectar uma possível falha de modelagem que pode estar causando problemas de performance.
Dicas para melhorar / corrigir as consultas são bem vindas.
Por hoje é só.
Clonando bases no ORACLE RAC 10G
2 de Junho de 2011, 0:00 - sem comentários aindaEu sempre fui fã do backup feito na mão. Gosto de ter controle do processo, adaptar um script para demandas específicas etc e tal. Mas quando utilizamos o Oracle RAC, em geral estamos utilizando o ASM e neste caso, a unica forma de se fazer backup físico é pelo RMAN.
Clonar uma base guardada em file system é simples. Você copia os datafiles, gera um controlfile, edita ele, faz um PITR e pronto. Mas com ASM você não pode fazer isso. Você vai ter de utilizar o nosso amigo DUPLICATE.
Bom eu queria escrever algo detalhado, explicando cada passo, mas a preguiça me impediu. Então vamos apenas mostrar o cenário do exemplo e mandar bala logo:
- Oracle RAC 10.2.0.5 com 2 nós.
- A base a ser clonada é a ‘producao’ com as instâncias ‘producao1′ e ‘producao2′
- A base que vai ser atualizada/criada com os dados da’producao’ é a base’teste’ cin as instâncias ‘teste1′ e ‘teste2′.
- As duas bases tem suas instâncias nos dois servidores, ora1 e ora2 utilizando um SO UNIX like.
- A base ‘produção’ está utilizando o diskgroup ASMGRP01 e ASMGRP02.
- A base ‘teste’ utiliza apenas o diskgroup ASMGRP03
- Estou supondo que a base ‘teste’ já existe, e vai ser atualizada. Se a base não existir, o processo muda. Você não precisa apagar a base antes, mas precisa criar o init e os diretórios nos nós. Não vou abordar estes detalhes aqui.
Preparação
Passo1 - Verificar em quais diskgroups os arquivos da base teste estão
export ORACLE_SID=teste sqlplus /nolog conn / as sysdba SELECT name FROM v$datafile; SELECT * FROM v$logfile; SELECT value FROM v$parameter WHERE name = 'control_files'; exit
Passo2 - baixar a base no RAC
srvctl stop database -d teste
Passo3 – Apagar a base no ASM
Tome cuidado aqui. Vamos excluir os arquivos dos diskgroups observados no passo 1.
export ORACLE_SID=+ASM asmcmd cd asmgrp03 rm -r teste exit
Passo 4 – Editar init
Aqui não estou utilizando SPFILE, pois o 10g tem um bug que ocorre com o SPFILE durante o duplicate no 10g)
cd $ORACLE_HOME/dbs vi initteste.ora
- Alterar os seguintes parâmetros :
*.control_files = '+ASMGRP03' *.CLUSTER_DATABASE = FALSE
- Verifique o nome do parâmetro UNDO_TABLESPACE. O nome da tablespace deve ser idêntico ao UNDO da produção. No caso deste duplicate, tive de fazer um ajuste, pois o parâmetro do UNDO estava errado no init.
- Configure os parâmetros para alterar o diretório de destino. Neste caso, vamos mandar os datafiles e REDO dos diskgroups ASMGRP01 e ASMGRP02 todos para ASMGRP03:
db_file_name_convert = ('+ASMGRP01/producao','+ASMGRP03/teste', '+ASMGRP02/producao','+ASMGRP03/teste', '+ASMGRP03/producao','+ASMGRP03/teste') log_file_name_convert = ('+ASMGRP01/producao','+ASMGRP03/teste', '+ASMGRP02/producao','+ASMGRP03/teste', '+ASMGRP03/producao','+ASMGRP03/teste')
- Configure o parâmetro para evitar um bug durante o RESETLOGS do DUPLICATE:
_no_recovery_through_resetlogs=TRUE
Passo 5 – Fazer o backup em disco da base de produção.
Se já houver um backup recente, pode pular esta etapa. É fundamental que no backup tenha ocorrido um
sql ‘alter system archive log current’;
No caso abaixo o
backup database plus archivelog
faz isso implicitamente. Se resolver fazer o backup de outra forma, sembre-se disso.
export ORACLE_SID=producao rman target / <<EOF backup database plus archivelog; exit EOF
Enfim o DUPLICATE
Passo 6 - Realizar o DUPLICATE com o nohup
É importante rodar isto com o nohup para evitar surpresas. Na verdade no próprio backup também é importante. Então eu crio o script:
export ORACLE_SID=teste rman TARGET sys/sua_senha@producao NOCATALOG AUXILIARY sys/sua_senha <<EOF RUN { ALLOCATE AUXILIARY CHANNEL aux1 DEVICE TYPE DISK; DUPLICATE TARGET DATABASE TO teste; RELEASE AUXILIARY CHANNEL aux1; } EXIT EOF
e rodo ele com o comando:
nohup atualizaTeste.sh
Verifique o log do nohup.out e veja se está ok.
tail -f nohup.out
Passo 7 – Verificar o controlfile gerado:
export ORACLE_SID=teste sqlplus /nolog <<EOF SELECT value FROM v$parameter WHERE name = 'control_files'; exit EOF
Passo 8 – Baixar a base
export ORACLE_SID=teste sqlplus /nolog <<EOF shutdown immediate exit EOF
Passo 9 – Editar novamente o init
Colocar o parâmetro ‘control_files’ com o valor encontrado no passo 7.
Colocar o parâmetro ‘cluster_database’ com o valor TRUE.
Copiar o init editado para o nó 2:
scp initteste01.ora ora2:$ORACLE_HOME/dbs/initteste2.ora
Passo 10 – Subir a base no modo NOARCHIVE
export ORACLE_SID=teste sqlplus /nolog <<EOF startup mount ALTER database noarchivelog; ALTER database open; EOF
Habilitando a base no 2º nó
Se você chegou aqui, parabéns. Eu demorei um tempinho até fazer isso com sucesso pleno. Mas tem um detalhe importante, ao duplicar a base, apenas um nó é duplicado, o outro nó continua inativo.
Passo 11 – Verificar o UNDO
Verifique se o UNDO dos 2 nós estão presentes.
export ORACLE_SID=teste sqlplus /nolog <<EOF SELECT tablespace_name, status FROM dba_tablespaces WHERE contents = 'UNDO'; exit EOF
Se não estiver, criar para o nó 2
Passo 12 – Criar o REDO para o nó 2
Antes verifique como os logs de REDO estão:
SELECT * FROM v$log; -- olhar o tamanho dos logs select * FROM v$logfile; -- olhar o destino e quantidade dos logs;
Depois crie os logs para a thread 2 segundo as informações encontradas. Neste caso, serão 4 REDOs, de 512M com um membro por grupo utilizando o diskgroup ASMGRP03.
ALTER database add logfile thread 2 ('+asmgrp03') size 512M; ALTER database add logfile thread 2 ('+asmgrp03') size 512M; ALTER database add logfile thread 2 ('+asmgrp03') size 512M; ALTER database add logfile thread 2 ('+asmgrp03') size 512M;
Passo 13 – Habilitar o nó 2
ALTER database enable thread 2;
Passo 14 – baixar a base
shutdown immediate
Passo 15 Verificar se a base está cadastrada no cluster
Como a base em geral está sendo atualizada, este problema não ocorre, pois já deverá estar OK. Mas se você estiver criando uma nova, com certeza vai precisar mexer nisso. De qualquer forma, é sempre bom checar.
cd $CRS_HOME/bin/crs_stat
Tem de aparecer algo como:
NAME=ora.teste.db TYPE=application TARGET=OFFLINE STATE=OFFLINE on ora02 NAME=ora.teste.teste1.inst TYPE=application TARGET=OFFLINE STATE=OFFLINE on ora01 NAME=ora.teste.teste2.inst TYPE=application TARGET=OFFLINE STATE=OFFLINE on ora02
Se não aparecerem as linhas, cadastrar a base no cluster:
srvctl add database -d teste -o $ORACLE_HOME srvctl add instance -d teste -i teste1 -n ora01 srvctl add instance -d teste -i teste2 -n ora02
Legenda:
- -d = nome da base
- -o = local do $ORACLE_HOME
- -I = instância
- -n = mome do servidor onde a instância está.
Passo 16 – Subir a base nos 2 nós pelo cluster
srvctl start database -d teste
Passo 17 – Verificar nos 2 nós
Você pode ignorar alguns erros logo depois do recover, no momento do resetlogs, mas fique atendo a todo o restante.
Na verdade, durante todo o processo é uma boa idéia ir acompanhando o alerta.
E se a base de testes não está no mesmo servidor, não está em RAC e ASM?
Bom, aí meu caro, você vai ter que tomar alguns cuidados adicionais:
- Você vai rodar o duplicate no servidor onde está a base de testes. Então precisa configurar o tnsnames.ora para a produção neste servidor. Configure para se conectar em um nó apenas.
- Você vai ter que tomar mais cuidado ainda no FILE_NAME_CONVERT.
- Você vai ter de criar os logs de REDO no próprio comando DUPLICATE.
- Você provavelmente vai pegar o backup da fita, então pegue a string de conexão do backup, mas altere o canal (channel em inglês) para auxiliar.
- Você vai poder apagar o tablespace UNDO do nó 2 que você não vai precisar.
- Você vai ter de tomar um mega cuidado com os archives. Quando o DUPLICATE roda com a produção e testes no mesmo servidor, nós configuramos o archive_dest da base teste igual ao da base de produção e não nos preocupamos mais com isso. Agora estão em servidores diferentes…
Exemplo 1
Ao invés de ficar aqui explicando tudo novamente, vou mostrar 2 exemplos de DUPLICATE de uma base em RAC para uma base de testes sem RAC:
rman TARGET sys/sua_senha@producao NOCATALOG AUXILIARY / <<EOF run { allocate auxiliary channel 'dev_0' type 'sbt_tape' parms 'SBT_LIBRARY=/opt/omni/lib/libob2oracle8_64bit.so,ENV=(OB2BARTYPE=Oracle8,OB2APPNAME=producao01,OB2BARLIST=PRODUCAO_DIARIO)'; send device type 'sbt_tape' 'OB2BARHOSTNAME=ora1'; DUPLICATE TARGET DATABASE TO teste UNTIL TIME "TRUNC(SYSDATE) + 3/24 + 40/1440" DB_FILE_NAME_CONVERT = ( '+ASMGRP01/producao/datafile/', '/u01/oradata/teste/', '+ASMGRP01/producao/tempfile/', '/u01/oradata/teste/') LOGFILE GROUP 1 ('/u01/oradata/teste/redo01.log') SIZE 128M REUSE, GROUP 2 ('/u01/oradata/teste/redo02.log') SIZE 128M REUSE, GROUP 3 ('/u01/oradata/teste/redo03.log') SIZE 128M REUSE, GROUP 4 ('/u01/oradata/teste/redo04.log') SIZE 128M REUSE; release auxiliary channel 'dev_0'; } EXIT EOF
Algumas observações:
- Este backup está vindo de uma fita, então estou passando alguns parâmetros específicos para um software de backup, que não vem ao caso aqui. Mas fique atento que sem os dados de um log de backup para fita da sua ferramenta de backup, você não tem como pegar os parâmetros em “params” logo no começo;
- O parâmetro “UNTIL TIME” está ajustado para um horário bem específico, referente à janela de backup da unidade de fitas, e é um horário depois do término do backup normal e antes do horário em que eu rodei um backup dos archives na mão;
- Eu coloquei o DB_FILE_NAME_CONVERT aqui no DUPLICATE e não no INIT. Se estiver configurado este parâmetro no init também, vale o do DUPLICATE.
- O LOGFILE é um dos segredos do sucesso. Ao invés de configurar o LOG_FILE_NAME_CONVERT, eu digo logo como ele tem de ficar. Me poupa o trabalho de arrumar isso depois.
- Você não precisa, mas seria bom remover o tablespace de UNDO do nó 2, que não estará sendo utilizado.
Exemplo 2
Agora vou mostrar um script que utilizo para uma base D-1. Ou seja, uma base que faz o restore do backup da produção todo dia:
export ORACLE_HOME=/opt/app/oracle/product/10.2.0/db_1 export PATH=/usr/local/bin:/bin:/usr/bin:$ORACLE_HOME/bin export ORACLE_SID=teste sqlplus / as sysdba <<EOF shutdown abort startup nomount EOF rm -fr /u01/oradata/teste/ rman TARGET sys/sua_senha@producao NOCATALOG AUXILIARY sys/sua_senha@teste <<EOF CONFIGURE DEVICE TYPE SBT_TAPE PARALLELISM 1 BACKUP TYPE TO BACKUPSET; CONFIGURE CHANNEL DEVICE TYPE 'SBT_TAPE' PARMS 'ENV=(OB2BARTYPE=Oracle8,OB2APPNAME=producao1,OB2BARLIST=PRODUCAO FULL)'; CONFIGURE DEFAULT DEVICE TYPE TO 'SBT_TAPE'; RUN { DUPLICATE TARGET DATABASE TO teste UNTIL TIME "TRUNC(SYSDATE) + 2/24 + 50/1440" OPEN RESTRICTED DB_FILE_NAME_CONVERT = ( '+ASMGRP01/producao/datafile/', '/u01/oradata/teste/', '+ASMGRP02/producao/datafile/', '/u01/oradata/teste/', '+ASMGRP01/producao/tempfile/', '/u01/oradata/teste/') LOGFILE GROUP 1 ('/u01/oradata/teste/redo01.log') SIZE 128M REUSE, GROUP 2 ('/u01/oradata/teste/redo02.log') SIZE 128M REUSE, GROUP 3 ('/u01/oradata/teste/redo03.log') SIZE 128M REUSE, GROUP 4 ('/u01/oradata/teste/redo04.log') SIZE 128M REUSE; } EXIT EOF
Comentários:
- Este script é uma forma simplificada de um script que fica agendado no crontab e roda toda noite.
- Note que a base abre no modo restrito.