問題タブ [mvcc]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
postgresql - PostgreSQL トランザクション ID (xmin) はコミットされたバージョンに順番に表示されますか?
PostgreSQL ドキュメントによるhttps://www.postgresql.org/docs/current/ddl-system-columns.html
xminこの行バージョンの挿入トランザクションの ID (トランザクション ID) (行バージョンは行の個々の状態です。行を更新するたびに、同じ論理行の新しい行バージョンが作成されます)。
同期データと PostgreSQL ソース DB からの変更 (ETL の E) の抽出に使用しています (理由は聞かないでください)。 0 から 10002 まで、次の同期を行うときに、この場合は 10003 から始まる xmin を検索します。コミットされ可視化された各トランザクションが順番に番号付けされている場合、問題はありません。すべてのデータ変更は順番に番号付けされますが、トランザクションが初期化された時点で番号付けされている場合、次のケースが発生する可能性があります。
- トランザクション 10001 は 15:01 に開始されました
- トランザクション 10002 は 15:02 に開始されました
- トランザクション 10002 が 15:02 にコミットされました
- トランザクション 10001 が 15:03 にコミットされました
15:02 に同期を行い、ターゲット DB で最大 xmin を取得した場合: 10002 この場合、xmin 10003 から始まる次の同期で xmin 10001 をスキップし、変更が失われます。
では、PostgreSQL トランザクション ID (xmin) はコミットされたバージョンに順番に表示されますか?
同じドキュメントに xmax もあります:
xmax削除するトランザクションの ID (トランザクション ID)、または削除されていない行バージョンの場合は 0。表示される行バージョンでは、この列がゼロ以外になる可能性があります。これは通常、削除するトランザクションがまだコミットされていないか、削除の試行がロールバックされたことを示します。
行の削除を計画しているトランザクション (コミットされる場合) を見ることができるので、xmin には行を変更するトランザクションも表示されるのではないでしょうか? しかし、これは xmin の説明のために当てはまりません:
...この行バージョンの場合。(行バージョンは、行の個々の状態です。行を更新するたびに、同じ論理行の新しい行バージョンが作成されます。)
書かれているように、それは私たちが読んだ行のバージョンと一致しなければならないため、おそらくダーティリード (コミットされていないデータが表示されたとき) でのみ可能ですが、これは PostgreSQL https://www.postgresql.org/docs/currentでは発生しません。 /transaction-iso.html
ダーティ リード: 許可されていますが、PG では許可されていません
sql - txidを使用して最新の処理されていない更新された行を取得する
PostgreSQL にテーブル (実際には複数のテーブルがありますが、簡単にするために 1 つだけと仮定します) と、変更された項目を見つけるために定期的にテーブルにクエリを実行する必要がある複数のクライアントがあります。これらは更新または挿入されたアイテムです (削除されたアイテムは、最初に削除のマークを付けてから、猶予期間後に実際に削除することによって処理されます)。
明らかな解決策は、各行の「変更された」タイムスタンプ列を保持し、各クライアントごとにそれを覚えてから、変更されたものを単純にフェッチすることです
変更された列は、次のようなトリガーを使用して最新の状態に保たれます。
ここで明らかな問題はNOW()
、トランザクションが開始された時間です。そのため、更新された行のフェッチ中にトランザクションがまだコミットされておらず、トランザクションがコミットされたときに、タイムスタンプが saved_modified_timestamp よりも小さいため、更新が登録されないことがあります。
うまくいく解決策を見つけたと思います。このアプローチで欠陥を見つけることができるかどうかを確認したかったのです。
基本的な考え方は、タイムスタンプの代わりに xmin (またはむしろtxid_current()
) を使用し、変更を取得するときに明示的なトランザクションでそれらをラップし、トランザクションから(または含まれる 3 つの値を)REPEATABLE READ
読み取ることです。txid_snapshot()
txid_snapshot_xmin()
txid_snapshot_xmax()
txid_snapshot_xip()
postgres のドキュメントを正しく読んだ場合、<txid_snapshot_xmax()
であり、含まれていないトランザクションで行われたすべての変更txid_snapshot_xip()
は、そのフェッチ トランザクションで返されるはずです。この情報は、再度フェッチするときにすべての更新行を取得するために必要なすべてです。列をxmin_version
置き換えると、選択は次のようになります。modified
トリガーは次のようになります。
これは機能しますか?または、何か不足していますか?
mysql - MySQL でのデフォルトの同時実行制御の実装
MySQL での同時実行制御のデフォルトの実装は何ですか? 楽観的ロック (複数バージョン同時実行制御) ですか、それとも悲観的ロック (2 フェーズ ロック) ですか? より具体的には、InnoDb はどのようにそれを行うのでしょうか? 内部的に、mysql (innodb を使用) はトランザクションの開始時に、行をロックするか、競合後にロールバックするかをどのように決定しますか?