Obtenir la date de dernière modification d'une table de base de données PostgreSQL

35

J'essaie de voir quand ma table a été modifiée en vérifiant la date de modification de son fichier telle qu'elle est décrite dans cette réponse . Mais le résultat n'est pas toujours correct. La date de modification du fichier est mise à jour quelques minutes après la mise à jour de mon tableau. Est-ce comportement correct? PostgreSQL ™ stocke-t-il les modifications de table dans un cache, puis le vide sur le disque dur?

Alors, comment puis-je obtenir la date de dernière modification correcte d'un tableau (supposons que les modifications par aspiration automatique sont également acceptables)?

J'utilise PostgreSQL 9.2 sous Linux Centos 6.2 x64.

écheveau
la source
4
Je ne pense pas que l'heure de modification du fichier est fiable. Cela pourrait aussi changer en raison de l'autovacuum. Le seul moyen fiable est de stocker un horodatage de modification dans votre table, maintenu par un déclencheur.
a_horse_with_no_name
Une idée serait que les informations stockées dans les fichiers WAL soient écrites dans les fichiers de données quelque temps (plus court ou plus long) après la validation de la transaction. Si vous le souhaitez, vous pouvez appeler cela un cache :) Sinon, j'appuie ce que @a_horse_with_no_name a dit.
dezso

Réponses:

35

Il n’existe aucun enregistrement fiable et faisant autorité de la dernière heure modifiée d’une table. L'utilisation du relfilenode est fausse pour de nombreuses raisons:

  • Les écritures sont initialement enregistrées dans le journal de la tête d’écriture (WAL), puis par la suite dans le tas (les fichiers de la table). Une fois que l'enregistrement est dans WAL, Pg ne s'empresse pas de l'écrire dans le tas, et il est même possible qu'il ne soit pas écrit avant le prochain point de contrôle système.

  • Les tables plus grandes ont plusieurs fourchettes, vous devez vérifier toutes les fourches et choisir le dernier horodatage;

  • Un simple SELECTpeut générer une activité d'écriture sur la table sous-jacente en raison de la définition de l'indice binaire;

  • La maintenance automatique et les autres opérations de maintenance qui ne modifient pas les données visibles de l'utilisateur modifient toujours les fichiers de relation;

  • certaines opérations, par exemple vaccum full, remplaceront le relfilenode. Ce n'est peut-être pas ce à quoi vous vous attendez si vous essayez de l'examiner simultanément sans verrouiller de manière appropriée.

Quelques options

Si vous n'avez pas besoin de fiabilité, vous pouvez potentiellement utiliser les informations dans pg_stat_databaseet pg_stat_all_tables. Ceux-ci peuvent vous donner l'heure de la dernière réinitialisation des statistiques et des statistiques d'activité depuis la dernière réinitialisation des statistiques. Cela ne vous dit pas quand était la dernière activité, mais seulement depuis la dernière réinitialisation des statistiques, et il n'y a aucune information sur ce qui s'est passé avant cette réinitialisation. Donc, c'est limité, mais c'est déjà là.

Une option pour le faire de manière fiable consiste à utiliser un déclencheur pour mettre à jour une table contenant les heures de dernière modification pour chaque table. Sachez que cela sérialisera toutes les écritures dans la table , détruisant ainsi la concurrence. Cela ajoutera également pas mal de frais généraux à chaque transaction. Je ne le recommande pas.

Une alternative légèrement moins terrible consiste à utiliser LISTENet NOTIFY. Demandez à un processus démon externe de se connecter à PostgreSQL et LISTENaux événements. Utilisez des ON INSERT OR UPDATE OR DELETEdéclencheurs pour envoyer des messages NOTIFYquand une table est modifiée, avec la table oid comme charge utile de notification. Ceux-ci sont envoyés lorsque la transaction est validée. Votre démon peut accumuler des notifications de changement et les écrire paresseusement dans une table de la base de données. Si le système se bloque, vous perdez votre liste des modifications les plus récentes, mais ce n'est pas grave, vous ne faites que modifier toutes les tables comme si elles venaient d'être modifiées si vous démarrez après une panne.

Pour éviter le pire des problèmes de simultanéité, vous pouvez plutôt enregistrer les horodatages de changement à l'aide d'un before insert or update or delete or truncate on tablename for each statement executedéclencheur, généralisé pour prendre la relation oid en tant que paramètre. Cela insérerait une (relation_oid, timestamp)paire dans une table de journalisation des modifications. Vous avez ensuite un processus d'assistance sur une connexion distincte ou appelé périodiquement par votre application, agrégez cette table pour obtenir les informations les plus récentes, fusionnez-la dans un tableau récapitulatif des modifications les plus récentes et tronquez la table de journalisation. Le seul avantage de cette approche par rapport à l’écoute / notification est qu’elle ne perd pas d’informations sur les collisions - mais elle est aussi moins efficace.

Une autre approche pourrait consister à écrire une fonction d'extension C qui utilise (par exemple) ProcessUtility_hook, ExecutorRun_hooketc à des changements de table de pièges et paresseusement les statistiques de mise à jour. Je n'ai pas cherché à voir comment cela serait pratique; Jetez un coup d'œil aux différentes options de _hook dans les sources.

Le meilleur moyen serait de corriger le code de statistiques pour enregistrer ces informations et de soumettre un correctif à PostgreSQL pour l'inclure dans le noyau. Ne commencez pas simplement par écrire du code; soulevez votre idée sur les hackers une fois que vous y avez suffisamment réfléchi pour avoir un moyen bien défini de le faire (c.-à-d. commencez par lire le code, ne vous contentez pas de demander "comment puis-je ..."). Il peut être intéressant d’ajouter à la dernière mise à jour pg_stat_..., mais vous devez convaincre la communauté que cela en vaut la peine ou fournir un moyen de le suivre éventuellement - et vous devez écrire le code pour conserver les statistiques et soumettez un correctif , car seul celui qui souhaite utiliser cette fonctionnalité s’ennuiera de cela.

Comment je le ferais

Si je devais le faire et que je n'avais pas le temps d'écrire un correctif pour le faire correctement, j'utiliserais probablement l'approche d'écoute / notification décrite ci-dessus.

Mise à jour des horodatages de validation de PostgreSQL 9.5

Mise à jour : PostgreSQL 9.5 a des timestamps . Si vous les avez activé dans postgresql.conf(et l' ont fait dans le passé aussi), vous pouvez vérifier l'horodatage commettras de la ligne avec le plus grand xminpour se rapprocher de la dernière modification. Ce n'est qu'une approximation car si les lignes les plus récentes ont été supprimées, elles ne seront pas comptabilisées.

De plus, les enregistrements d'horodatage de validation ne sont conservés que pendant un temps limité. Donc, si vous voulez savoir quand une table qui n'est pas modifiée beaucoup est modifiée, la réponse sera effectivement "ne sait pas, il y a quelque temps".

Craig Ringer
la source
17

PostgreSQL 9.5 nous permet de suivre le dernier commit modifié.

  1. La validation de la piste de contrôle est activée ou désactivée à l'aide de la requête suivante

    show track_commit_timestamp;
  2. Si la réponse est "ON", passez à l'étape 3 sinon modifiez postgresql.conf

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

    Changement

    track_commit_timestamp = off

    à

    track_commit_timestamp = on

    Redémarrez le système

    Répétez l'étape 1.

  3. Utilisez la requête suivante pour suivre le dernier 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;
Thirumal
la source
1
Vous n'avez pas à redémarrer le système à l'étape 2. Il vous suffit de redémarrer le processus. par exemple sudo service postgresql restart.
ijoseph
3

Oui, on peut s’attendre à ce qu’il se comporte - les données sur les modifications sont immédiatement stockées dans le journal des transactions. Les fichiers de données peuvent être mis à jour avec un délai checkpoint_timeout (5 minutes par défaut). Postgres ne tient pas en permanence à tout moment que vous demandez.

Pavel Stehule
la source
Je ne suis pas sûr de comprendre comment cela répond à la question. Oui, les données sont stockées dans le journal des transactions, mais cela ne signifie pas que l'on peut facilement obtenir une heure de modification pour une table spécifique ( si ce contenu est toujours dans le journal, il est possible d'analyser le journal, mais les choses sont relues plutôt rapidement).
Charles Duffy
Bien sûr, vous pouvez obtenir toutes les informations nécessaires à partir du journal, mais les questions ont été posées à mtime des fichiers de données - l’actualisation des fichiers de données peut être assez aléatoire - quelques secondes - quelques minutes (maximum 1 heure) après la validation.
Pavel Stehule
L’opération a elle-même tenté de consulter des fichiers, mais leur véritable objectif est clairement d’obtenir une table mtime. Mais oui, je comprends où vous voulez en venir (en expliquant pourquoi cela ne fonctionnait pas) maintenant.
Charles Duffy
2

J'ai presque la même exigence pour conserver un cache de certaines tables sur une application cliente. Je dis presque , car je n'ai pas vraiment besoin de connaître l'heure de la dernière modification, mais seulement de détecter si quelque chose a changé depuis la dernière synchronisation du cache.

Voici mon approche:

Si vous avez une colonne id(PK), created_on(horodatage d'insertion) et updated_on(timestamp de mise à jour, peut être NULL) sur chaque table, vous pouvez

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

Si vous concattez cela et que vous ajoutez le nombre de lignes, vous pouvez créer une balise de version qui ressemble à celle count:id#timestamp-ci et qui sera unique pour chaque version des données de la table.

laurent
la source