Obtendo a data da última modificação de uma tabela de banco de dados PostgreSQL

35

Estou tentando saber quando minha tabela foi modificada verificando sua data de modificação do arquivo, conforme descrito nesta resposta . Mas o resultado nem sempre é correto. A data de modificação do arquivo é atualizada em alguns minutos após a atualização da minha tabela. É um comportamento correto? O PostgreSQL armazena modificações de tabelas em algum cache e depois as libera para o disco rígido?

Então, como obtenho a data correta da última modificação de uma tabela (vamos supor que as modificações automáticas de vácuo também estejam corretas)?

Eu uso o PostgreSQL 9.2 no Linux Centos 6.2 x64.

hank
fonte
4
Não acho que a hora da modificação do arquivo seja confiável. Também pode mudar devido ao vácuo automático. A única maneira confiável é armazenar um carimbo de data / hora de modificação em sua tabela, mantido por um gatilho.
A_horse_with_no_name
Uma idéia seria que as informações armazenadas nos arquivos WAL sejam gravadas nos arquivos de dados algum tempo (mais curto ou mais longo) após a confirmação da transação. Se quiser, você pode chamar isso de cache :) Caso contrário, eu entendo o que @a_horse_with_no_name disse.
Dezso

Respostas:

35

Não há nenhum registro confiável e autoritário do horário da última modificação de uma tabela. O uso do relfilenode está errado por vários motivos:

  • As gravações são inicialmente registradas no WAL (write-head log) e depois preguiçosamente no heap (os arquivos da tabela). Quando o registro está no WAL, a página não se apressa em gravá-lo no heap e pode até não ser gravado até o próximo ponto de verificação do sistema;

  • Tabelas maiores têm vários garfos, você precisará verificar todos os garfos e escolher o carimbo de data / hora mais recente;

  • Um simples SELECTpode gerar atividade de gravação na tabela subjacente devido à configuração do bit de dica;

  • autovaccum e outras manutenções que não alteram os dados visíveis do usuário ainda modificam os arquivos de relação;

  • algumas operações, como vaccum full, substituirão o relfilenode. Pode não ser o esperado, se você estiver tentando visualizá-lo simultaneamente sem usar o bloqueio apropriado.

Algumas opções

Se você não precisar de confiabilidade, poderá usar as informações em pg_stat_databasee pg_stat_all_tables. Isso pode indicar o horário da última redefinição de estatísticas e as atividades desde a última redefinição. Ele não informa quando foi a atividade mais recente, apenas que ocorreu desde a última redefinição de estatísticas e não há informações sobre o que aconteceu antes da redefinição dessas estatísticas. Portanto, é limitado, mas já está lá.

Uma opção para fazer isso de forma confiável é usar um gatilho para atualizar uma tabela que contém os horários da última modificação para cada tabela. Esteja ciente de que isso serializará todas as gravações na tabela , destruindo a simultaneidade. Ele também adicionará um pouco de sobrecarga a todas as transações. Eu não recomendo.

Uma alternativa um pouco menos terrível é usar LISTENe NOTIFY. Tenha um processo de daemon externo conectado ao PostgreSQL e LISTENpara eventos. Use ON INSERT OR UPDATE OR DELETEgatilhos para enviar NOTIFYs quando uma tabela for alterada, com a tabela oid como carga útil de notificação. Eles são enviados quando a transação é confirmada. Seu daemon pode acumular notificações de alteração e gravá-las lentamente em uma tabela no banco de dados. Se o sistema travar, você perderá o registro das modificações mais recentes, mas tudo bem, você tratará todas as tabelas como modificadas apenas se estiver iniciando após uma falha.

Para evitar os piores problemas de simultaneidade, você pode registrar os carimbos de data / hora da mudança usando um before insert or update or delete or truncate on tablename for each statement executegatilho, generalizado para usar a relação oid como parâmetro. Isso inseriria um (relation_oid, timestamp)par em uma tabela de registro de alterações. Você tem um processo auxiliar em uma conexão separada ou chamado periodicamente pelo seu aplicativo, agrega essa tabela para obter as informações mais recentes, mescla-a em uma tabela de resumo das alterações mais recentes e trunca a tabela de log. A única vantagem disso em relação à abordagem de ouvir / notificar é que ela não perde informações em caso de falha - mas é ainda menos eficiente também.

Outra abordagem poderia ser a de escrever uma função de extensão C que usa (por exemplo) ProcessUtility_hook, ExecutorRun_hook, etc à mesa alterações armadilha e estatísticas de atualização preguiçosamente. Não olhei para ver como isso seria prático; dê uma olhada nas várias opções _hook nas fontes.

A melhor maneira seria corrigir o código estatístico para registrar essas informações e enviar um patch ao PostgreSQL para inclusão no núcleo. Não basta começar escrevendo código; aumente sua idéia em -hackers quando você pensar sobre isso o suficiente para ter uma maneira bem definida de fazê-lo (por exemplo, comece lendo o código, não apenas poste perguntando "como faço para ..."). Pode ser bom acrescentar os horários da última atualização pg_stat_..., mas você precisa convencer a comunidade de que vale a pena a sobrecarga ou fornecer uma maneira de torná-la opcionalmente rastreada - e você deve escrever o código para manter as estatísticas e envie um patch , porque apenas alguém que deseja esse recurso se incomodará com isso.

Como eu faria isso

Se eu tivesse que fazer isso e não tivesse tempo de escrever um patch para fazê-lo corretamente, provavelmente usaria a abordagem de ouvir / notificar descrita acima.

Atualização para os carimbos de data e hora do commit do PostgreSQL 9.5

Atualização : O PostgreSQL 9.5 possui registros de data e hora . Se você os tiver ativado postgresql.conf(e também o fez no passado), poderá verificar o registro de data e hora da confirmação com a maior linha xminpara aproximar a hora da última modificação. É apenas uma aproximação, porque se as linhas mais recentes forem excluídas, elas não serão contadas.

Além disso, os registros de registro de data e hora de confirmação são mantidos apenas por um tempo limitado. Portanto, se você quiser saber quando uma tabela que não é muito modificada é modificada, a resposta será efetivamente "não sei, há um tempo atrás".

Craig Ringer
fonte
17

O PostgreSQL 9.5 permite rastrear a confirmação da última modificação.

  1. Verifique se o commit da faixa está ativado ou desativado usando a seguinte consulta

    show track_commit_timestamp;
  2. Se retornar "ON", vá para a etapa 3, modifique o postgresql.conf

    cd /etc/postgresql/9.5/main/
    vi postgresql.conf

    mudança

    track_commit_timestamp = off

    para

    track_commit_timestamp = on

    Reinicie o sistema

    Repita a etapa 1.

  3. Use a seguinte consulta para rastrear a última confirmação

    SELECT pg_xact_commit_timestamp(xmin), * FROM  YOUR_TABLE_NAME;
    
    SELECT pg_xact_commit_timestamp(xmin), * FROM YOUR_TABLE_NAME where COLUMN_NAME=VALUE;
Thirumal
fonte
11
Você não precisa reiniciar o sistema na etapa 2. apenas reinicie o processo. por exemplo sudo service postgresql restart.
precisa saber é
3

Sim, isso pode ser esperado - dados sobre alterações são armazenados no log de transações imediatamente. Os arquivos de dados podem ser atualizados com atraso no ponto de verificação_timeout (o padrão é 5 minutos). O Postgres não se mantém permanentemente a qualquer momento que você solicita.

Pavel Stehule
fonte
Não sei ao certo como isso responde à pergunta. Sim, os dados são armazenados no log de transações, mas isso não significa que é possível obter um tempo de modificação para uma tabela específica facilmente ( se esse conteúdo ainda estiver no log, é possível analisar o log, mas as coisas são reproduzidas rapidamente).
Charles Duffy
Certamente, você pode obter todas as informações necessárias no log, mas as perguntas foram direcionadas ao mtime dos arquivos de dados - a atualização dos arquivos de dados pode ser bem aleatória - alguns segundos - alguns minutos (no máximo 1 hora) após a confirmação.
Pavel Stehule 14/09/16
A própria tentativa do OP foi através da busca de arquivos, mas a intenção real deles é claramente obter uma hora de mesa. Mas sim, entendo de onde você vem daqui (explicando por que o que eles estavam fazendo não funcionou) agora.
Charles Duffy
2

Tenho quase o mesmo requisito para manter um cache de algumas tabelas em um aplicativo cliente. Digo quase , porque realmente não preciso saber a hora da última modificação, mas apenas para detectar se algo mudou desde a última vez em que o cache foi sincronizado.

Aqui está a minha abordagem:

Desde que você tenha uma coluna id(PK), created_on(registro de data e hora de inserção) e updated_on(registro de data e hora de atualização, pode ser NULL) em todas as tabelas, você pode

SELECT id,greatest(created_on,updated_on) FROM %s ORDER BY greatest(created_on,updated_on) DESC LIMIT 1;

Se você concatenar isso e preceder o número de linhas, poderá criar uma tag de versão parecida count:id#timestampe será exclusiva para todas as versões dos dados na tabela.

Laurent
fonte