web-dev-qa-db-ja.com

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

最も単純なケースでは、新しい行をテーブルに挿入すると(そしてトランザクションがコミットすると)、それは後続のすべてのトランザクションから見えるようになります。この例では、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
_

[〜#〜] mvcc [〜#〜] PostgreSQLが使用するモデルによると、新しい物理行が書き込まれ、古い行が無効化されました(これは 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が何かに設定されています。これにもかかわらず、後続のトランザクションはこの(そうでなければ変更されていない)行を見ることができます。

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

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

_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年から存続していた次のものは、2702年に_HEAP_XMAX_INVALID_から見たUPDATEのロールバック試行がありました。
_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の内部を調べる方法はありますか?以前のバージョンのPostgresでのclogの破損についての言及と、偽のファイルを手動で作成できるというヒントがあります。この情報は、非常に役立ちます。
10
dezso

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

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

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

heap_xmin_committedまたはheap_xmin_invalidがない場合は、クロッグにアクセスして、xminの性質を確認する必要があります。トランザクションがまだ進行中の場合、行は表示されず、フラグを設定できません。トランザクションがコミットまたはロールバックされた場合は、heap_xmin_committedまたはheap_xmin_invalidを適宜設定します(これが便利な場合-必須ではありません)。将来の人々はそれを調べる必要がありません。 。

xminが有効でコミットされており、xmaxがゼロではなく、heap_max_committedまたはheap_max_invalidがない場合は、clogにアクセスして何を確認する必要がありますそのトランザクションの性質はそうでした。

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

ユーザーフレンドリーな方法を私は知りません。 "od"を使用して、clogファイルを適切な方法でダンプして検査し、src/backend/access/transam/clog.cで定義されたマクロを使用して検査する場所を特定できます。

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

6
jjanes

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

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

4
alex