sábado, 27 de novembro de 2010

PostgreSQL - Usando o pgbench

Como todos sabem, o 'pgbench' é uma ferramenta muito útil para testar tuning no PostgreSQL, lembrando que para comparar retornos do 'pgbench' deve-se ter o mesmo cenário antes e depois do tuning, não adianta executar o 'pgbench' em horário comercial e depois do tuning rodá-lo novamente na madrugada. O ideal é executá-lo quando o banco está dedicado a você.

Pacote que instala o 'pgbench' no RHEL: postgresql-contrib

Primeiro é necessário criar a database onde o 'pgbench' executará as transações, pode ser via 'psql' ou 'createdb'.

Para criar as estruturas na database que você criou:

# pgbench -i -s 10 database_criada -U postgres

-U neste caso é necessário porque estou executando o comando como 'root'.

Agora vamos ao teste:

# pgbench -c 90 -t 10 bmark -U postgres -n

-c 90 significa o número de clientes conectados, não deve superar o número de conexões disponíveis no seu postgresql.conf

-t 10 o número de transações por cliente

-n não executar autovacuum para iniciar as transações

Antes de executar um benchmark sugiro atualizar as estatísticas do banco, bem como os índices, para que melhore o plano de execução e tempo de consulta do seu banco de dados.

quarta-feira, 24 de novembro de 2010

Oracle - Solucionando erro ORA-00257

Problema: ORA-00257: archiver error. Connect internal only, until freed.

Sintoma: Aceita apenas conexões internas e rejeita externas, o banco está aberto, mas não aceita transações em razão de um redo log travado.

Passo 1 - Baixe a database.

SQL> SHUTDOWN IMMEDIATE;
ORACLE instance shut down.

Passo 2 - Inicie em modo de manutenção.

SQL> STARTUP MOUNT
ORACLE instance started.
Total System Global Area 1191182336 bytes
Fixed Size 2020320 bytes
Variable Size 318770208 bytes
Database Buffers 855638016 bytes
Redo Buffers 14753792 bytes
Database mounted.


Passo 3 (não execute) - Ocorre erro ao tentar "abrir" a database, mencionando que não
pode gravar o arquivo de redo.


SQL> ALTER DATABASE OPEN;
ALTER DATABASE OPEN
*
ERROR at line 1:
ORA-16038: log 1 sequence# 53 cannot be archived
ORA-19809: limit exceeded for recovery files
ORA-00312: online log 1 thread 1:
'/u01/app/oracle/product/10.2.0/oradata/orcl/redo01.log'


Passo 4 - Validando o destino e se está em modo archive, veja que o espaço da Flash
Recovery Area está lotado, causa do problema. 


SQL > SELECT * FROM V$RECOVERY_FILE_DEST;
NAME
--------------------------------------------------------------------------------
SPACE_LIMIT SPACE_USED SPACE_RECLAIMABLE NUMBER_OF_FILES
----------- ---------- ----------------- ---------------
/u01/app/oracle/product/10.2.0/flash_recovery_area/ 2147483648 2141670912 0 50

Passo 5 - Mova os archives antigo da Flash Recovery Area para outro local. E inicie o
RMAN.

$ rman target sys/senha@SID

Passo 6 - No RMAN valide os archives e apague os antigos.

RMAN > CROSSCHECK ARCHIVELOG ALL;
using target database control file instead of recovery catalog
allocated channel: ORA_DISK_1
channel ORA_DISK_1: sid=151 devtype=DISK
RMAN > DELETE EXPIRED ARCHIVELOG ALL;


Passo 7 - Saia do RMAN e conectado na instância localmente altere o tamanho da Flash
Recovery Area.


RMAN > exit;
SQL> ALTER SYSTEM SET DB_RECOVERY_FILE_DEST_SIZE=4294967296 SCOPE=BOTH;

Passo 8 - Suba a database, alterando o estado para 'OPEN'.
SQL> ALTER DATABASE OPEN;
Database altered..

PostgreSQL - Remover arquivos WAL antigos que já foram "backupeados"

Um problema para quem utiliza o PostgreSQL em modo archive é que depois de fazer backup dos mesmos com o 'pg_rman' eles permanecem no disco. Com o tempo o disco ficará cheio e o que era para ser uma solução vira uma dor de cabeça.

Com isso criei um script em Perl que remove os archives mais antigos que já foram "backupeados". Os archives serão apagados se e somente se o último backup com o 'pg_rman' esteja validado com o status de 'OK'. A variável '$opt_date' deve ser utilizada fornecendo o número de archives criados antes do último backup que deseja manter em disco.

Código:


#!/usr/bin/perl

# Author: Gabriel Prestes
# Last modified: 11-24-2010
# Fuction: Recycle WAL backed in PostgreSQL

($opt_date) = @ARGV;

        # --- Doc --- #
        # WAL after backup example: 00000001000000000000004B.00000020.backup
        # --- Doc --- #

        # --- VARS --- #
        my @list=();
        my @list2=();
        my @stat=();
        my $wal_path="/data/archive_log";
        my $backup_catalog="/var/lib/pgsql/backup_catalog";
        my $lastbkp="";
        my $cmd="";
        my $counter=0;
        my $flag=0;
        my $flagok=0;
        my $pointrecycle="";

        if(!$opt_date){

                print "ERROR - Please insert number of WAL to keep after recycle\n";
                exit(1);

        }

        @list=`/bin/ls -t $wal_path`;
        @list2=`/usr/bin/pg_rman show -B $backup_catalog`;

        # -- CHECK first WAL backup --- #
        foreach(@list){

                chomp($_);
                if($_ =~ ".backup"){

                        @stat=`/usr/bin/stat $wal_path/$_`;
                        foreach(@stat){chomp($_);if($_ =~ m/^Modify: (.+) [0-9].+$/){$lastbkp=$1;last;}}
                        print "BACKUP LOCATED $wal_path/$_ - done in '$lastbkp'\n";
                        $pointrecycle=$_;
                        last;

                }

        }

        # --- CHECK last backup done with success --- #
        foreach(@list2){

                chomp($_);
                if($_ =~ $lastbkp and $_ =~ "OK"){

                        print "LAST VALIDATED BACKUP IS '$_'\n";
                        $flagok++;
                        last;

                }

        }

        # --- Thresholds --- #
        if($flagok>0){

                # --- Remove old WALs --- #
                foreach(@list){

                        chomp($_);
                        if($flag == 1){$counter++;}
                        if($_ =~ $pointrecycle){$flag++;}
                        if($flag == 1 and $counter > 0 and $counter <= $opt_date){print "OLD WAL '$_' PRESERVED\n";}
                        if($flag == 1 and $counter > 0 and $counter > $opt_date){print "OLD WAL '$_' REMOVED\n"; $cmd=`/bin/rm -f $wal_path/$_`; sleep(01);}

                }

        }

        else{

                print "LAST BACKUP RUN WITH ERRORS\n - WALS FILES NOT REMOVED\n";

        }



# EOF