AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 5110
Accepted
gsiems
gsiems
Asked: 2011-08-27 10:48:35 +0800 CST2011-08-27 10:48:35 +0800 CST 2011-08-27 10:48:35 +0800 CST

Determinar quando um banco de dados PostgreSQL foi alterado pela última vez

  • 772

Estou procurando alterar como os backups são feitos e estou me perguntando se existe uma maneira de determinar quais bancos de dados em um cluster postgreql não foram alterados recentemente?

Em vez de usar pg_dumpall, gostaria de usar pg_dump e despejar apenas os bancos de dados que foram alterados desde o último backup (alguns bancos de dados não são atualizados com muita frequência) - a ideia é que, se nada mudou, o backup atual deve ainda ser bom.

Alguém conhece uma maneira de determinar quando um banco de dados específico foi atualizado/alterado pela última vez?

Obrigado...

Atualizar:

Eu esperava não ter que escrever gatilhos em todo o lugar, pois não tenho controle sobre a criação de bancos de dados em um cluster específico (muito menos a criação de objetos de banco de dados em um banco de dados).

Indo mais fundo, parece que há uma correlação entre o conteúdo do arquivo $PGDATA/global/pg_database (especificamente o segundo campo) e os nomes de diretório em $PGDATA/base.

Indo em um membro, eu acho que o segundo campo do arquivo pg_database é o id do banco de dados e que cada banco de dados tem seu próprio subdiretório em $PGDATA/base (com o oid para o nome do subdiretório). Isso é correto? Em caso afirmativo, é razoável usar os registros de data e hora dos arquivos em $PGDATA/base/* como o gatilho para a necessidade de um backup?

...Ou há um modo melhor?

Obrigado novamente...

postgresql backup
  • 5 5 respostas
  • 11027 Views

5 respostas

  • Voted
  1. Best Answer
    gsiems
    2011-09-01T09:53:52+08:002011-09-01T09:53:52+08:00

    Embora o uso select datname, xact_commit from pg_stat_database;sugerido por @Jack Douglas não funcione (aparentemente devido ao autovacuum), select datname, tup_inserted, tup_updated, tup_deleted from pg_stat_databaseparece funcionar. As alterações DML e DDL alterarão os valores das colunas tup_* enquanto a vacuumnão ( vacuum analyzepor outro lado...).

    Na chance de que isso possa ser útil para outras pessoas, estou incluindo o script de backup que coloquei em prática. Isso funciona para Pg 8.4.x, mas não para 8.2.x-- YMMV, dependendo da versão do Pg usada.

    #!/usr/bin/env perl
    =head1 Synopsis
    
    pg_backup -- selectively backup a postgresql database cluster
    
    =head1 Description
    
    Perform backups (pg_dump*) of postgresql databases in a cluster on an
    as needed basis.
    
    For some database clusters, there may be databases that are:
    
     a. rarely updated/changed and therefore shouldn't require dumping as 
        often as those databases that are frequently changed/updated.
    
     b. are large enough that dumping them without need is undesirable.
    
    The global data is always dumped without regard to whether any 
    individual databses need backing up or not.
    
    =head1 Usage
    
    pg_backup [OPTION]...
    
    General options:
    
      -F, --format=c|t|p    output file format for data dumps 
                              (custom, tar, plain text) (default is custom)
      -a, --all             backup (pg_dump) all databases in the cluster 
                              (default is to only pg_dump databases that have
                              changed since the last backup)
      --backup-dir          directory to place backup files in 
                              (default is ./backups)
      -v, --verbose         verbose mode
      --help                show this help, then exit
    
    Connection options:
    
      -h, --host=HOSTNAME   database server host or socket directory
      -p, --port=PORT       database server port number
      -U, --username=NAME   connect as specified database user
      -d, --database=NAME   connect to database name for global data
    
    =head1 Notes
    
    This utility has been developed against PostgreSQL version 8.4.x. Older 
    versions of PostgreSQL may not work.
    
    `vacuum` does not appear to trigger a backup unless there is actually 
    something to vacuum whereas `vacuum analyze` appears to always trigger a 
    backup.
    
    =head1 Copyright and License
    
    Copyright (C) 2011 by Gregory Siems
    
    This library is free software; you can redistribute it and/or modify it 
    under the same terms as PostgreSQL itself, either PostgreSQL version 
    8.4 or, at your option, any later version of PostgreSQL you may have 
    available.
    
    =cut
    
    use strict;
    use warnings;
    use Getopt::Long;
    use Data::Dumper;
    use POSIX qw(strftime);
    
    my %opts = get_options();
    
    my $connect_options = '';
    $connect_options .= "--$_=$opts{$_} " for (qw(username host port));
    
    my $shared_dump_args = ($opts{verbose})
        ? $connect_options . ' --verbose '
        : $connect_options;
    
    my $backup_prefix = (exists $opts{host} && $opts{host} ne 'localhost')
        ? $opts{backup_dir} . '/' . $opts{host} . '-'
        : $opts{backup_dir} . '/';
    
    do_main();
    
    
    ########################################################################
    sub do_main {
        backup_globals();
    
        my $last_stats_file = $backup_prefix . 'last_stats';
    
        # get the previous pg_stat_database data
        my %last_stats;
        if ( -f $last_stats_file) {
            %last_stats = parse_stats (split "\n", slurp_file ($last_stats_file));
        }
    
        # get the current pg_stat_database data
        my $cmd = 'psql ' . $connect_options;
        $cmd .= " $opts{database} " if (exists $opts{database});
        $cmd .= "-Atc \"
            select date_trunc('minute', now()), datid, datname, 
                xact_commit, tup_inserted, tup_updated, tup_deleted 
            from pg_stat_database 
            where datname not in ('template0','template1','postgres'); \"";
        $cmd =~ s/\ns+/ /g;
        my @stats = `$cmd`;
        my %curr_stats = parse_stats (@stats);
    
        # do a backup if needed
        foreach my $datname (sort keys %curr_stats) {
            my $needs_backup = 0;
            if ($opts{all}) {
                $needs_backup = 1;
            }
            elsif ( ! exists $last_stats{$datname} ) {
                $needs_backup = 1;
                warn "no last stats for $datname\n" if ($opts{debug});
            }
            else {
                for (qw (tup_inserted tup_updated tup_deleted)) {
                    if ($last_stats{$datname}{$_} != $curr_stats{$datname}{$_}) {
                        $needs_backup = 1;
                        warn "$_ stats do not match for $datname\n" if ($opts{debug});
                    }
                }
            }
            if ($needs_backup) {
                backup_db ($datname);
            }
            else {
                chitchat ("Database \"$datname\" does not currently require backing up.");
            }
        }
    
        # update the pg_stat_database data
        open my $fh, '>', $last_stats_file || die "Could not open $last_stats_file for output. !$\n";
        print $fh @stats;
        close $fh;
    }
    
    sub parse_stats {
        my @in = @_;
        my %stats;
        chomp @in;
        foreach my $line (@in) {
            my @ary = split /\|/, $line;
            my $datname = $ary[2];
            next unless ($datname);
            foreach my $key (qw(tmsp datid datname xact_commit tup_inserted tup_updated tup_deleted)) {
                my $val = shift @ary;
                $stats{$datname}{$key} = $val;
            }
        }
        return %stats;
    }
    
    sub backup_globals {
        chitchat ("Backing up the global data.");
    
        my $backup_file = $backup_prefix . 'globals-only.backup.gz';
        my $cmd = 'pg_dumpall --globals-only ' . $shared_dump_args;
        $cmd .= " --database=$opts{database} " if (exists $opts{database});
    
        do_dump ($backup_file, "$cmd | gzip");
    }
    
    sub backup_db {
        my $database = shift;
        chitchat ("Backing up database \"$database\".");
    
        my $backup_file = $backup_prefix . $database . '-schema-only.backup.gz';
        do_dump ($backup_file, "pg_dump --schema-only --create --format=plain $shared_dump_args $database | gzip");
    
        $backup_file = $backup_prefix . $database . '.backup';
        do_dump ($backup_file, "pg_dump --format=". $opts{format} . " $shared_dump_args $database");
    }
    
    sub do_dump {
        my ($backup_file, $cmd) = @_;
    
        my $temp_file = $backup_file . '.new';
        warn "Command is: $cmd > $temp_file" if ($opts{debug});
    
        chitchat (`$cmd > $temp_file`);
        if ( -f $temp_file ) {
            chitchat (`mv $temp_file $backup_file`);
        }
    }
    
    sub chitchat {
        my @ary = @_;
        return unless (@ary);
        chomp @ary;
        my $first   = shift @ary;
        my $now     = strftime "%Y%m%d-%H:%M:%S", localtime;
        print +(join "\n                  ", "$now $first", @ary), "\n";
    }
    
    sub get_options {
        Getopt::Long::Configure('bundling');
    
        my %opts = ();
        GetOptions(
            "a"             => \$opts{all},
            "all"           => \$opts{all},
            "p=s"           => \$opts{port},
            "port=s"        => \$opts{port},
            "U=s"           => \$opts{username},
            "username=s"    => \$opts{username},
            "h=s"           => \$opts{host},
            "host=s"        => \$opts{host},
            "F=s"           => \$opts{format},
            "format=s"      => \$opts{format},
            "d=s"           => \$opts{database},
            "database=s"    => \$opts{database},
            "backup-dir=s"  => \$opts{backup_dir},
            "help"          => \$opts{help},
            "v"             => \$opts{verbose},
            "verbose"       => \$opts{verbose},
            "debug"         => \$opts{debug},
            );
    
        # Does the user need help?
        if ($opts{help}) {
            show_help();
        }
    
        $opts{host}         ||= $ENV{PGHOSTADDR} || $ENV{PGHOST}     || 'localhost';
        $opts{port}         ||= $ENV{PGPORT}     || '5432';
        $opts{host}         ||= $ENV{PGHOST}     || 'localhost';
        $opts{username}     ||= $ENV{PGUSER}     || $ENV{USER}       || 'postgres';
        $opts{database}     ||= $ENV{PGDATABASE} || $opts{username};
        $opts{backup_dir}   ||= './backups';
    
        my %formats = (
            c       => 'custom',
            custom  => 'custom',
            t       => 'tar',
            tar     => 'tar',
            p       => 'plain',
            plain   => 'plain',
        );
        $opts{format} = (defined $opts{format})
            ? $formats{$opts{format}} || 'custom'
            : 'custom';
    
        warn Dumper \%opts if ($opts{debug});
        return %opts;
    }
    
    sub show_help {
        print `perldoc -F $0`;
        exit;
    }
    
    sub slurp_file { local (*ARGV, $/); @ARGV = shift; <> }
    
    __END__
    

    Atualização: o script foi colocado no github aqui .

    • 9
  2. Jack Douglas
    2011-08-28T01:07:39+08:002011-08-28T01:07:39+08:00

    Parece que você pode usar pg_stat_databasepara obter uma contagem de transações e verificar se isso muda de uma execução de backup para a seguinte:

    select datname, xact_commit from pg_stat_database;
    
      datname  | xact_commit 
    -----------+-------------
     template1 |           0
     template0 |           0
     postgres  |      136785
    

    Se alguém ligou, pg_stat_resetvocê não pode ter certeza se um banco de dados mudou ou não, mas pode considerar bastante improvável que isso aconteça, seguido pelo número exato de transações para corresponder à sua última leitura.

    --EDITAR

    veja esta pergunta SO para saber por que isso pode não funcionar. Não sei por que isso pode acontecer, mas habilitar o log pode lançar alguma luz ....

    • 2
  3. Jack Douglas
    2011-08-27T16:07:57+08:002011-08-27T16:07:57+08:00

    De vasculhar os documentos e grupos de notícias do postgres:

    txid_current()lhe dará um novo xid- se você chamar a função novamente em uma data posterior, se você obtiver xidum maior, você saberá que nenhuma transação foi confirmada entre as duas chamadas. Você pode obter falsos positivos - por exemplo, se outra pessoa ligartxid_current()

    • 1
  4. Nils
    2011-08-28T12:58:53+08:002011-08-28T12:58:53+08:00

    Lembre-se do carimbo de data/hora em seus arquivos contendo os dados do banco de dados e verifique se eles foram alterados. Se o fizessem, havia uma gravação.

    Editar após dica do WAL: Você deve fazer isso somente após liberar as gravações pendentes.

    • 0
  5. Thirumal
    2017-04-01T03:48:49+08:002017-04-01T03:48:49+08:00

    O Postgresql 9.5 nos permite rastrear o registro de data e hora da última modificação, confira este link https://thirumal-opensource.blogspot.in/2017/03/to-track-last-modified-commit-or-get.html

    • 0

relate perguntas

  • Práticas recomendadas para executar a replicação atrasada do deslocamento de tempo

  • Backups de banco de dados no Oracle - Exportar o banco de dados ou usar outras ferramentas?

  • Os procedimentos armazenados impedem a injeção de SQL?

  • Sequências Biológicas do UniProt no PostgreSQL

  • Qual é a diferença entre a replicação do PostgreSQL 9.0 e o Slony-I?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Como você mostra o SQL em execução em um banco de dados Oracle?

    • 2 respostas
  • Marko Smith

    Como selecionar a primeira linha de cada grupo?

    • 6 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Posso ver Consultas Históricas executadas em um banco de dados SQL Server?

    • 6 respostas
  • Marko Smith

    Como uso currval() no PostgreSQL para obter o último id inserido?

    • 10 respostas
  • Marko Smith

    Como executar o psql no Mac OS X?

    • 11 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Marko Smith

    Passando parâmetros de array para um procedimento armazenado

    • 12 respostas
  • Martin Hope
    Manuel Leduc Restrição exclusiva de várias colunas do PostgreSQL e valores NULL 2011-12-28 01:10:21 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Stuart Blackler Quando uma chave primária deve ser declarada sem cluster? 2011-11-11 13:31:59 +0800 CST
  • Martin Hope
    pedrosanta Listar os privilégios do banco de dados usando o psql 2011-08-04 11:01:21 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST
  • Martin Hope
    BrunoLM Guid vs INT - Qual é melhor como chave primária? 2011-01-05 23:46:34 +0800 CST
  • Martin Hope
    bernd_k Quando devo usar uma restrição exclusiva em vez de um índice exclusivo? 2011-01-05 02:32:27 +0800 CST
  • Martin Hope
    Patrick Como posso otimizar um mysqldump de um banco de dados grande? 2011-01-04 13:13:48 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve