Implémentation de mises à jour de client incrémentielles avec rowversions dans Postgres

Je suis un nouveau venu chez Postgres et je l'aime jusqu'à présent. J'ai déjà beaucoup réfléchi à ce problème, RTFM au mieux de mes capacités, mais je suis dans une impasse, alors j'ai besoin d'un coup de pouce dans la bonne direction.

Je conçois une database où chaque entité d'intérêt a une colonne rowversion qui reçoit une valeur d'une séquence globale. Donc, dans le scénario le plus simple, dans une table emps avec deux lignes: emp1 avec rowversion@3 et emp2 avec rowversion@5 , je sais emp2 été modifié après emp1 (ie dans une transaction ultérieure – ne pas vraiment déranger si les lignes dans le la même transaction a la même rowversion ).

Ceci est à la base d'une logique de synchronisation de données , où un client qui sait tout avoir jusqu'à 3, peut get les dernières mises à jour en utilisant une requête telle que SELECT * FROM emps WHERE rowversion>3 and rowversion<=new_anchor .

Voici un exemple de scénario pour un client déjà mis à jour @ 3 – Supposons les transactions suivantes depuis:

 @3 - committed @4 - committed @5 - committed @6 - in progress - not committed yet @7 - committed @8 - in progress - not committed yet @9 - committed 

La mise à jour du client est effectuée en trois étapes:

  1. Demandez à la database un nouveau new_anchor approprié.
  2. Exécutez SELECT * FROM emps WHERE rowversion>3 and rowversion<=new_anchor .
  3. new_anchor valeur new_anchor au client, avec datatables de résultat.

Puisque les lignes avec rowversion @ 6 et @ 8 sont toujours en cours, new_anchor doit être @ 5, de sorte que notre requête range ne manque aucune mise à jour non validée . Maintenant, le client peut être sûr qu'il a tout jusqu'à @ 5.

Donc, le problème réel distillé: comment ce new_anchor peut- new_anchor être déterminé en toute security sans forcer SERIALIZABLE ou autrement gravement blesser la performance?

Comme vous pouvez probablement le dire, j'ai emprunté cette idée à SQL Server, où ce problème est sortingvialement résolu par la fonction min_active_rowversion() . Cette fonction returnnera @ 6 dans le scénario ci-dessus, ainsi votre new_anchor peut être min_active_rowversion() - 1 . J'ai en quelque sorte eu une idée de comment cela pourrait être implémenté dans Postgres en utilisant une table active_rowversions , des sortingggers, et SELECT min(id) FROM active_rowversions , mais cela nécessiterait l'isolation READ UNCOMMITTED , qui n'est pas disponible dans Postgres.

J'apprécierais vraiment n'importe quelle aide ou idées.

Il s'avère que la solution est beaucoup plus simple que prévu, grâce aux fonctions d'information système de Postgres.

  • txid_current() peut être utilisé dans un sortinggger pour assigner la rowversion un logging.
  • txid_snapshot_min(txid_current_snapshot()) peut être utilisé pour get la transaction active minimale de la même manière qu'un user SQL Server peut utiliser min_active_rowversion() .

La meilleure partie est ce sont 64 bits, permanents, non soumis à l'aspiration:

Ces fonctions exportent un format 64 bits qui est étendu avec un countur "epoch" afin qu'il ne s'enroule pas pendant la durée de vie d'une installation.

Postgres est vraiment incroyable.