Ottenere la data dell'ultima modifica di una tabella del database PostgreSQL


35

Sto cercando di capire quando la mia tabella è stata modificata verificandone la data di modifica come descritto in questa risposta . Ma il risultato non è sempre corretto. La data di modifica del file si aggiorna tra qualche minuto dopo l'aggiornamento della mia tabella. È un comportamento corretto? PostgreSQL memorizza le modifiche della tabella in una cache e quindi la scarica sul disco rigido?

Quindi, come posso ottenere la data dell'ultima modifica corretta di una tabella (supponiamo che anche le modifiche del vuoto automatico siano ok)?

Uso PostgreSQL 9.2 in Linux Centos 6.2 x64.


4
Non credo che il tempo di modifica del file sia affidabile. Potrebbe anche cambiare a causa del vuoto automatico. L'unico modo affidabile è memorizzare un timestamp di modifica nella tabella, gestito da un trigger.
a_horse_with_no_name

Un'idea sarebbe che le informazioni memorizzate nei file WAL vengano scritte nei file di dati un tempo (più o meno lungo) dopo aver eseguito la transazione. Se vuoi, puoi chiamarlo cache :) Altrimenti, secondo quello che ha detto @a_horse_with_no_name.
dezso

Risposte:


35

Non esiste un record affidabile e autorevole dell'ora dell'ultima modifica di una tabella. L'uso del relfilenode è errato per molte ragioni:

  • Le scritture vengono inizialmente registrate nel registro testina di scrittura (WAL), quindi pigramente nell'heap (i file della tabella). Una volta che il record è in WAL, Pg non si affretta a scriverlo nell'heap e potrebbe non essere nemmeno scritto fino al successivo checkpoint di sistema;

  • Le tabelle più grandi hanno più fork, dovresti controllare tutte le fork e scegliere il timestamp più recente;

  • Un semplice SELECTpuò generare attività di scrittura nella tabella sottostante a causa dell'impostazione del bit di suggerimento;

  • l'autovaccum e altri tipi di manutenzione che non modificano i dati visibili dell'utente modificano ancora i file delle relazioni;

  • alcune operazioni, come vaccum full, sostituiranno il relfilenode. Potrebbe non essere quello che ti aspetti se stai cercando di guardarlo contemporaneamente senza prendere un blocco appropriato.

Alcune opzioni

Se non hai bisogno di affidabilità, puoi potenzialmente utilizzare le informazioni in pg_stat_databasee pg_stat_all_tables. Questi possono dare il tempo dell'ultimo azzeramento statistiche, e le statistiche di attività fin dall'ultimo azzeramento statistiche. Non ti dice quando è stata l'attività più recente, solo che è stata dall'ultimo reset delle statistiche, e non ci sono informazioni su ciò che è accaduto prima del ripristino delle statistiche. Quindi è limitato, ma è già lì.

Un'opzione per farlo in modo affidabile è utilizzare un trigger per aggiornare una tabella contenente i tempi dell'ultima modifica per ogni tabella. Tieni presente che così facendo serializzerai tutte le scritture sul tavolo , distruggendo la concorrenza. Aggiungerà anche un bel po 'di sovraccarico a ogni transazione. Non lo consiglio.

Un'alternativa leggermente meno terribile è usare LISTENe NOTIFY. Avere un processo daemon esterno connettersi a PostgreSQL e LISTENper eventi. Usa i ON INSERT OR UPDATE OR DELETEtrigger per inviare messaggi NOTIFYquando una tabella cambia, con la tabella oid come payload di notifica. Questi vengono inviati quando viene eseguita la transazione. Il tuo demone può accumulare notifiche di modifica e scriverle pigramente su una tabella nel database. Se il sistema si arresta in modo anomalo, perdi il record delle modifiche più recenti, ma va bene, tratti solo tutte le tabelle come appena modificate se stai avviando dopo un arresto anomalo.

Per evitare il peggio dei problemi di concorrenza, è possibile invece registrare i timestamp di modifica utilizzando un before insert or update or delete or truncate on tablename for each statement executetrigger, generalizzato per prendere l'oid di relazione come parametro. Ciò inserirà una (relation_oid, timestamp)coppia in una tabella di registrazione delle modifiche. Quindi hai un processo di supporto su una connessione separata o chiamato periodicamente dalla tua app, aggrega quella tabella per le informazioni più recenti, uniscilo in una tabella di riepilogo delle modifiche più recenti e tronca la tabella di registro. L'unico vantaggio di questo rispetto all'approccio di ascolto / notifica è che non perde informazioni in caso di arresto anomalo, ma è anche meno efficiente.

Un altro approccio potrebbe essere quello di scrivere una funzione di estensione C che utilizzi (ad esempio) ProcessUtility_hook, ExecutorRun_hook, ecc per tabella cambia intrappolare e statistiche aggiornamento pigramente. Non ho cercato di vedere quanto sarebbe stato pratico; dai un'occhiata alle varie opzioni di _hook nelle fonti.

Il modo migliore sarebbe applicare una patch al codice statistico per registrare queste informazioni e inviare una patch a PostgreSQL per l'inclusione nel core. Non iniziare semplicemente scrivendo il codice; solleva la tua idea su -hackers una volta che ci hai pensato abbastanza per avere un modo ben definito di farlo (cioè iniziare leggendo il codice, non solo postare chiedendo "come posso ..."). Potrebbe essere utile aggiungere i tempi dell'ultimo aggiornamento pg_stat_..., ma dovresti convincere la community che valeva il sovraccarico o fornire un modo per tenerlo tracciato facoltativamente - e dovresti scrivere il codice per mantenere le statistiche e inviare una patch , perché solo qualcuno che desidera questa funzione si preoccuperà di questo.

Come lo farei

Se dovessi farlo, e non avessi il tempo di scrivere una patch per farlo correttamente, probabilmente userei l'approccio di ascolto / notifica descritto sopra.

Aggiornamento per i timestamp di commit di PostgreSQL 9.5

Aggiornamento : PostgreSQL 9.5 ha i timestamp di commit . Se li hai abilitati in postgresql.conf(e lo hai fatto anche in passato), puoi controllare il timestamp di commit per la riga con il massimo xminper approssimare l'ultima volta modificata. È solo un'approssimazione perché se le righe più recenti sono state eliminate non verranno conteggiate.

Inoltre, i record di data / ora del commit vengono conservati solo per un tempo limitato. Quindi, se vuoi dire quando una tabella che non è molto modificata viene modificata, la risposta sarà effettivamente "non so, poco fa".


17

PostgreSQL 9.5 ci permette di tracciare l'ultimo commit modificato.

  1. Verificare che il commit della traccia sia attivato o disattivato utilizzando la seguente query

    show track_commit_timestamp;
  2. Se restituisce "ON" vai al passaggio 3 altrimenti modifica postgresql.conf

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

    Modificare

    track_commit_timestamp = off

    a

    track_commit_timestamp = on

    Riavvia il sistema

    Ripeti il ​​passaggio 1.

  3. Utilizzare la seguente query per tenere traccia dell'ultimo commit

    SELECT pg_xact_commit_timestamp(xmin), * FROM  YOUR_TABLE_NAME;
    
    SELECT pg_xact_commit_timestamp(xmin), * FROM YOUR_TABLE_NAME where COLUMN_NAME=VALUE;

1
Non è necessario riavviare il sistema al passaggio 2. basta riavviare il processo. es sudo service postgresql restart.
ijoseph,

3

Sì, ci si può aspettare che questo si comporti: i dati relativi alle modifiche vengono archiviati immediatamente nel registro delle transazioni. I file di dati possono essere aggiornati con ritardo checkpoint_timeout (il valore predefinito è 5 minuti). Postgres non tiene permanentemente ogni volta che lo richiedi.


Non sono sicuro di capire come questo risponda alla domanda. Sì, i dati sono memorizzati nel registro delle transazioni, ma ciò non significa che si possa facilmente ottenere un tempo di modifica per una tabella specifica ( se quel contenuto è ancora nel registro si può analizzare il registro, ma le cose vengono riprodotte piuttosto velocemente).
Charles Duffy,

certo, puoi ottenere tutte le informazioni necessarie dal registro, ma le domande erano dirette al mtime dei file di dati - l'attualizzazione dei file di dati può essere piuttosto casuale - pochi secondi - pochi minuti (massimo 1 ora) dopo il commit.
Pavel Stehule,

Lo stesso tentativo del PO è stato quello di guardare i file, ma il loro vero intento è chiaramente quello di ottenere un tavolo. Ma sì, capisco da dove vieni (spiegando perché quello che stavano facendo non ha funzionato) ora.
Charles Duffy,

2

Ho quasi lo stesso requisito per mantenere una cache di alcune tabelle su un'applicazione client. Dico quasi , perché non ho davvero bisogno di sapere l'ora dell'ultima modifica, ma solo per rilevare se qualcosa è cambiato dall'ultima sincronizzazione della cache.

Ecco il mio approccio:

A condizione che tu abbia una colonna id(PK), created_on(timestamp di inserimento) e updated_on(aggiorna timestamp, potrebbe essere NULL) su ogni tabella, puoi

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

Se lo concatichi e anteponi il numero di righe, puoi creare un tag di versione che assomigli count:id#timestampe sarà univoco per ogni versione dei dati nella tabella.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.