Ich versuche herauszufinden, wann meine Tabelle geändert wurde, indem ich das in dieser Antwort beschriebene Änderungsdatum der Datei überprüfe . Das Ergebnis ist jedoch nicht immer korrekt. Das Änderungsdatum der Datei wird einige Minuten nach dem Aktualisieren meiner Tabelle aktualisiert. Ist es korrektes Verhalten? Speichert PostgreSQL Tabellenänderungen in einem Cache und speichert sie dann auf der Festplatte?
Wie erhalte ich das korrekte Datum der letzten Änderung einer Tabelle (nehmen wir an, dass die automatischen Vakuumänderungen ebenfalls in Ordnung sind)?
Ich benutze PostgreSQL 9.2 unter Linux Centos 6.2 x64.
postgresql
Strang
quelle
quelle
Antworten:
Es gibt keine zuverlässige, autorisierende Aufzeichnung des letzten Änderungszeitpunkts einer Tabelle. Die Verwendung des relfilenode ist aus vielen Gründen falsch:
Schreibvorgänge werden zunächst im Schreibkopfprotokoll (WAL) und dann träge im Heap (den Tabellendateien) aufgezeichnet . Sobald der Datensatz in WAL ist, beeilt sich Pg nicht, ihn auf den Heap zu schreiben, und er wird möglicherweise erst beim nächsten Systemprüfpunkt geschrieben.
Größere Tabellen haben mehrere Gabeln. Sie müssen alle Gabeln überprüfen und den neuesten Zeitstempel auswählen.
Ein einfacher Befehl
SELECT
kann aufgrund der Einstellung des Hinweisbits Schreibaktivitäten für die zugrunde liegende Tabelle generieren.Autovaccum und andere Wartungsarbeiten, die die vom Benutzer angezeigten Daten nicht ändern, ändern weiterhin die Beziehungsdateien.
Einige Operationen, wie zum Beispiel
vaccum full
, ersetzen den relfilenode. Es ist möglicherweise nicht der Ort, den Sie erwarten, wenn Sie versuchen, es gleichzeitig zu betrachten, ohne ein entsprechendes Schloss zu öffnen.Ein paar Möglichkeiten
Wenn Sie keine Zuverlässigkeit benötigen, können Sie die Informationen möglicherweise in
pg_stat_database
und verwendenpg_stat_all_tables
. Diese können Ihnen den Zeitpunkt des letzten Zurücksetzens der Statistiken und die Aktivitätsstatistik seit dem letzten Zurücksetzen der Statistiken anzeigen. Es gibt keine Auskunft darüber, wann die letzte Aktivität stattgefunden hat, nur darüber, dass sie seit dem letzten Zurücksetzen der Statistiken stattgefunden hat, und es gibt keine Informationen darüber, was vor dem Zurücksetzen der Statistiken geschehen ist. Also ist es begrenzt, aber es ist schon da.Eine Möglichkeit, dies zuverlässig zu tun, besteht darin, einen Trigger zu verwenden, um eine Tabelle zu aktualisieren, die die zuletzt geänderten Zeiten für jede Tabelle enthält. Beachten Sie, dass dadurch alle Schreibvorgänge in die Tabelle serialisiert und die Parallelität zerstört wird. Außerdem wird jeder Transaktion ein gewisser Overhead hinzugefügt. Ich kann es nicht empfehlen.
Eine etwas weniger schreckliche Alternative ist die Verwendung von
LISTEN
undNOTIFY
. Stellen Sie über einen externen Daemon-Prozess eine Verbindung zu PostgreSQL undLISTEN
zu Ereignissen her. Verwenden SieON INSERT OR UPDATE OR DELETE
Trigger, umNOTIFY
s zu senden, wenn sich eine Tabelle ändert, wobei die Tabelle oid als Benachrichtigungsnutzlast dient. Diese werden gesendet, wenn die Transaktion festgeschrieben wird. Ihr Daemon kann Änderungsbenachrichtigungen sammeln und diese träge in eine Tabelle in der Datenbank zurückschreiben. Wenn das System abstürzt, gehen die Aufzeichnungen der letzten Änderungen verloren, aber das ist in Ordnung. Wenn Sie nach einem Absturz starten, werden nur alle Tabellen als gerade geändert behandelt.Um die schlimmsten Parallelitätsprobleme zu vermeiden, können Sie stattdessen die Änderungszeitstempel mithilfe eines
before insert or update or delete or truncate on tablename for each statement execute
Triggers protokollieren , der verallgemeinert wird, um die Relation oid als Parameter zu verwenden. Dies würde ein(relation_oid, timestamp)
Paar in eine Änderungsprotokollierungstabelle einfügen . Sie haben dann einen Hilfsprozess auf einer separaten Verbindung oder werden regelmäßig von Ihrer App aufgerufen, aggregieren diese Tabelle für die neuesten Informationen, führen sie in einer Übersichtstabelle der neuesten Änderungen zusammen und kürzen die Protokolltabelle. Der einzige Vorteil gegenüber dem Listen / Notify-Ansatz besteht darin, dass beim Absturz keine Informationen verloren gehen - aber es ist auch noch weniger effizient.Ein weiterer Ansatz könnte sein , eine C - Erweiterungsfunktion , dass Nutzungen (zB) zu schreiben
ProcessUtility_hook
,ExecutorRun_hook
etc. zu stoppen Tabellenänderungen und lazily Update Statistiken. Ich habe nicht nachgesehen, wie praktisch dies sein würde. Schauen Sie sich die verschiedenen _hook-Optionen in den Quellen an.Am besten patchen Sie den Statistikcode, um diese Informationen aufzuzeichnen, und senden Sie einen Patch an PostgreSQL, um ihn in den Core aufzunehmen. Beginnen Sie nicht einfach damit, Code zu schreiben. Wenden Sie sich an -hacker, wenn Sie genug darüber nachgedacht haben, um eine genau definierte Möglichkeit zu haben (dh lesen Sie zunächst den Code, und posten Sie nicht einfach die Frage, wie ich ...). Es mag nett sein, die zuletzt aktualisierten Zeiten hinzuzufügen
pg_stat_...
, aber Sie müssten die Community davon überzeugen, dass sich der Aufwand gelohnt hat, oder eine Möglichkeit bieten, ihn optional zu verfolgen - und Sie müssten den Code schreiben, um die Statistiken und Daten zu speichern Reichen Sie einen Patch ein , denn nur wer dieses Feature möchte, wird sich darum kümmern.Wie ich es machen würde
Wenn ich dies tun müsste und nicht die Zeit hätte, einen Patch zu schreiben, um es richtig zu machen, würde ich wahrscheinlich den oben beschriebenen Listen / Notify-Ansatz verwenden.
Update für PostgreSQL 9.5-Commit-Zeitstempel
Update : PostgreSQL 9.5 verfügt über festgeschriebene Zeitstempel . Wenn Sie sie aktiviert haben
postgresql.conf
(und dies auch in der Vergangenheit getan haben), können Sie den Commit-Zeitstempel für die Zeile mit dem größten Wert überprüfen, um die letzte geänderte Zeitxmin
zu approximieren . Dies ist nur eine Annäherung, da die zuletzt gelöschten Zeilen nicht gezählt werden.Commit-Zeitstempeldatensätze werden nur für eine begrenzte Zeit aufbewahrt. Wenn Sie also feststellen möchten, wann eine Tabelle, die nicht wesentlich geändert wurde, geändert wurde, lautet die Antwort "Keine Ahnung, vor einiger Zeit".
quelle
Mit PostgreSQL 9.5 können wir das zuletzt geänderte Commit nachverfolgen.
Überprüfen Sie anhand der folgenden Abfrage, ob das Track-Commit aktiviert oder deaktiviert ist
Wenn "ON" zurückgegeben wird, fahren Sie mit Schritt 3 fort, andernfalls ändern Sie postgresql.conf
Veränderung
zu
Starten Sie das System neu
Wiederholen Sie Schritt 1.
Verwenden Sie die folgende Abfrage, um das letzte Festschreiben zu verfolgen
quelle
sudo service postgresql restart
.Ja, dies kann erwartet werden - Daten über Änderungen werden sofort im Transaktionsprotokoll gespeichert. Datendateien können mit einer Verzögerung von checkpoint_timeout aktualisiert werden (Standard sind 5 Minuten). Postgres hält nicht permanent die Zeit, die Sie anfordern.
quelle
Ich habe fast die gleiche Anforderung, um einen Cache einiger Tabellen in einer Client-Anwendung zu verwalten. Ich sage fast , weil ich den Zeitpunkt der letzten Änderung nicht wirklich wissen muss, sondern nur um festzustellen, ob sich etwas geändert hat, seit der Cache das letzte Mal synchronisiert wurde.
Hier ist mein Ansatz:
Vorausgesetzt, Sie haben eine Spalte
id
(PK),created_on
(Einfügezeitstempel) undupdated_on
(Aktualisierungszeitstempel, kann NULL sein) in jeder Tabelle, können SieWenn Sie dies zusammenfassen und die Anzahl der Zeilen voranstellen, können Sie ein Versions-Tag erstellen , das aussieht
count:id#timestamp
und für jede Version der Daten in der Tabelle eindeutig ist.quelle