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:
new_anchor
approprié. SELECT * FROM emps WHERE rowversion>3 and rowversion<=new_anchor
. 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.