行の可視性はどの程度正確に決定されますか?


10

最も単純なケースでは、新しい行をテーブルに挿入すると(そしてトランザクションがコミットすると)、後続のすべてのトランザクションから見えるようになります。xmaxこの例では0であることを参照してください。

CREATE TABLE vis (
  id serial,
  is_active boolean
);

INSERT INTO vis (is_active) VALUES (FALSE);

SELECT ctid, xmin, xmax, * FROM vis;

  ctid xmin  xmax  id  is_active 
───────┼─────┼──────┼────┼───────────
 (0,1) 2699     0   1  f

これを更新すると(フラグがFALSE誤って設定されたため)、少し変更されます。

UPDATE vis SET is_active = TRUE;

SELECT ctid, xmin, xmax, * FROM vis;

 ctid  xmin  xmax  id  is_active 
──────┼──────┼──────┼────┼───────────
(0,2)  2700     0   1  t

PostgreSQLが使用するMVCCモデルによると、新しい物理行が書き込まれ、古い行が無効化されました(これはから確認できますctid)。新しいトランザクションは、後続のすべてのトランザクションで引き続き表示されます。

ここで、ロールバックすると興味深いことが起こりUPDATEます。

BEGIN;

    UPDATE vis SET is_active = TRUE;

ROLLBACK;

SELECT ctid, xmin, xmax, * FROM vis;

 ctid   xmin  xmax  id  is_active 
───────┼──────┼──────┼────┼───────────
 (0,2)  2700  2702   1  t

行バージョンは同じままですが、現在xmaxは何かに設定されています。これにもかかわらず、後続のトランザクションはこの(そうでなければ変更されていない)行を見ることができます。

これについて少し読んだ後、行の可視性についていくつかのことを理解できます。可視性マップがありますが、ページ全体が表示されているかどうかのみがわかります。行(タプル)レベルでは機能しません。次に、コミットログ(別名clog)がありますが、Postgres は、ログにアクセスする必要があるかどうかをどのように判断しますか?

情報マスクのビットを見て、可視性が実際にどのように機能するかを理解することにしました。それらを表示する最も簡単な方法は、pageinspect拡張機能を使用することです。設定されているビットを確認するために、それらを格納するテーブルを作成しました。

CREATE TABLE infomask (
  i_flag text,
  i_bits bit(16)
);

INSERT INTO infomask
VALUES 
('HEAP_HASNULL', x'0001'::bit(16)),
('HEAP_HASVARWIDTH', x'0002'::bit(16)),
('HEAP_HASEXTERNAL', x'0004'::bit(16)),
('HEAP_HASOID', x'0008'::bit(16)),
('HEAP_XMAX_KEYSHR_LOCK', x'0010'::bit(16)),
('HEAP_COMBOCID', x'0020'::bit(16)),
('HEAP_XMAX_EXCL_LOCK', x'0040'::bit(16)),
('HEAP_XMAX_LOCK_ONLY', x'0080'::bit(16)),
('HEAP_XMIN_COMMITTED', x'0100'::bit(16)),
('HEAP_XMIN_INVALID', x'0200'::bit(16)),
('HEAP_XMAX_COMMITTED', x'0400'::bit(16)),
('HEAP_XMAX_INVALID', x'0800'::bit(16)),
('HEAP_XMAX_IS_MULTI', x'1000'::bit(16)),
('HEAP_UPDATED', x'2000'::bit(16)),
('HEAP_MOVED_OFF', x'4000'::bit(16)),
('HEAP_MOVED_IN', x'8000'::bit(16)),
('HEAP_XACT_MASK', x'FFF0'::bit(16));

次に、私のvisテーブルのpageinspect内容を確認しました。これはヒープの物理的な内容を示しているため、表示されている行だけが返されるわけではありません。

SELECT t_xmin, t_xmax, string_agg(i_flag, ', ') FILTER (WHERE (t_infomask::bit(16) & i_bits)::integer::boolean)
  FROM heap_page_items(get_raw_page('vis', 0)),
       infomask
 GROUP BY t_xmin, t_xmax;

 t_xmin  t_xmax                       string_agg                      
────────┼────────┼──────────────────────────────────────────────────────
   2699    2700  HEAP_XMIN_COMMITTED, HEAP_XMAX_COMMITTED
   2700    2702  HEAP_XMIN_COMMITTED, HEAP_XMAX_INVALID, HEAP_UPDATED
   2702       0  HEAP_XMIN_INVALID, HEAP_XMAX_INVALID, HEAP_UPDATED

私は上記から理解することは、最初のバージョンは、トランザクション2699との生活に来て、そして成功した2700の新しいバージョンに置き換えられていることである
その後2700年以来、生きていた次の1、、の圧延バックの試みを持っていたUPDATEから見て、2702年にHEAP_XMAX_INVALID
で示されているように、最後のものは実際には決して生まれませんでしたHEAP_XMIN_INVALID

したがって、上記から推測すると、最初と最後のケースは明白です-それらはトランザクション2703以降ではもう見えません。
2つ目はどこかで検索する必要がありますclog。これは、コミットログ(別名)だと思います。

問題をさらに複雑にするために、その後のUPDATE結果は次のようになります。

 t_xmin  t_xmax                      string_agg                     
────────┼────────┼────────────────────────────────────────────────────
   2699    2700  HEAP_XMIN_COMMITTED, HEAP_XMAX_COMMITTED
   2702       0  HEAP_XMIN_INVALID, HEAP_XMAX_INVALID, HEAP_UPDATED
   2703       0  HEAP_XMAX_INVALID, HEAP_UPDATED
   2700    2703  HEAP_XMIN_COMMITTED, HEAP_UPDATED

ここでは、表示可能な候補がすでに2つあります。だから、最後に、これが私の質問です:

  • 私の仮定は、clogこれらの場合に可視性を判断するために注目すべき場所であるということですか?
  • どのフラグ(またはフラグの組み合わせ)がシステムにclog
  • 中身を調べる方法はありclogますか?clog以前のバージョンのPostgresの破損についての言及と、偽のファイルを手動で作成できるというヒントがあります。この情報は、それをサポートするのに役立ちます。

回答:


6

したがって、上記から推測すると、最初と最後のケースは明白です-それらはトランザクション2703以降ではもう見えません。2番目のものはどこかで検索する必要があります-私はそれがコミットログ(別名clog)だと思います。

2つ目はHEAP_XMAX_INVALIDです。つまり、誰かが既にそれを行っているので、それxmaxが中止されていることを確認し、「ヒントビット」を設定して、その行で再び詰まりにアクセスする必要がないようにするため、詰まりを調べる必要はありません。

どのフラグ(またはフラグの組み合わせ)がシステムに詰まりを訪問するように伝えますか?

そこにはある場合heap_xmin_committedまたはheap_xmin_invalid、あなたはXMINの処分が何であったか確認するために、詰まりを訪問する必要がありません。トランザクションがまだ進行中の場合、行は表示されず、フラグを設定することはできません。トランザクションがコミットまたはロールバックされた場合は、heap_xmin_committedまたはを設定しheap_xmin_invalid(それが便利な場合-必須ではありません)、将来の人々がそれを調べる必要がないようにします。

場合はxmin有効ではなく、コミット、および場合xmaxはゼロではなく、そこにはあるheap_max_committedheap_max_invalid、そして、あなたはその取引の気質が何であったか確認するために、詰まりを訪問する必要があります。

下駄の内容を調べる方法はありますか?以前のバージョンのPostgresでのclogの破損についての言及と、偽のファイルを手動で作成できるというヒントがあります。この情報は、それをサポートするのに役立ちます。

ユーザーフレンドリーな方法を知りません。「od」を使用して、clogファイルを適切な方法でダンプし、それらを検査し、で定義されたマクロを使用して検査する場所を見つけることができます。src/backend/access/transam/clog.c

PGXNに機能する拡張機能がないことに驚いていますが、見つかりませんでした。しかし、サーバーが実行されていないときに実際にこれを実行できるようにする必要があるため、それほど便利ではないと思います。


4

HeapTupleSatisfiesMVCC()の実装を見てclogください。実際のチェックはTransactionIdDidCommit()で行われますが、トランザクションステータスが情報マスクビット(HeapTupleHeaderXminCommitted()マクロ とその仲間)から推測できない場合にのみ呼び出されます。

pg_clog関数TransactionDidCommit()とへのアクセスをたどっTransactionDidAbort()て、それらがどこで呼び出されているかを調べましたHeapTupleSatisfiesMVCC()。質問に関連するコード内の唯一の場所がにあるようです。この関数のコードから、タプルに関連するinfomaskビットが設定されていない場合にのみ、実際のclogルックアップが発生することがわかります。コードは、HeapTupleHeaderXminCommitted()etなどでビットをチェックすることから始まります。そして、詰まりの検索は、ビットが設定されていない場合にのみ発生します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.