sql >> データベース >  >> RDS >> PostgreSQL

PostgreSQL Upsertは、システム列XMIN、XMAXなどを使用して、挿入された行と更新された行を区別します

    これは、詳細な回答に値する興味深い質問だと思います。少し長い場合はご容赦ください。

    要するに:あなたの推測は正しいです、そしてあなたは次のRETURNINGを使うことができます 行が挿入され、更新されていないかどうかを判断する句:

    RETURNING (xmax = 0) AS inserted
    

    ここで詳細な説明:

    行が更新されると、PostgreSQLはデータを変更しませんが、新しいバージョンを作成します。 行の;古いバージョンはautovacuumによって削除されます 不要になったとき。行のバージョンはタプルと呼ばれます したがって、PostgreSQLでは、行ごとに複数のタプルが存在する可能性があります。

    xmax 2つの異なる目的を果たします:

    1. ドキュメントに記載されているように、タプルを削除(または更新)したのはトランザクションのトランザクションIDである可能性があります(「タプル」は「行」の別の単語です)。 xmin間のトランザクションIDを持つトランザクションのみ およびxmax タプルを見ることができます。トランザクションIDがxmax未満のトランザクションがない場合は、古いタプルを安全に削除できます。 。

    2. xmax 行ロックの保存にも使用されます 。 PostgreSQLでは、行ロックはロックテーブルに保存されませんが、ロックテーブルのオーバーフローを回避するためにタプルに保存されます。
      行にロックがあるトランザクションが1つだけの場合は、xmax ロックトランザクションのトランザクションIDが含まれます。複数のトランザクションで行がロックされている場合は、xmax いわゆるmultixactの数が含まれています 、これは、ロックされているトランザクションのトランザクションIDを含むデータ構造です。

    xmaxのドキュメント このフィールドの正確な意味は実装の詳細と見なされ、t_infomaskを知らなければ理解できないため、は完全ではありません。 タプルの、SQLですぐには表示されません。

    contribモジュールpageinspectをインストールできます タプルのこのフィールドと他のフィールドを表示します。

    私はあなたの例を実行しました、そしてこれは私がheap_page_itemsを使用するときに私が見るものです 詳細を調べる機能(私の場合、トランザクションID番号はもちろん異なります):

    SELECT *, ctid, xmin, xmax FROM t;
    
    ┌───┬────┬───────┬────────┬────────┐
    │ i │ x  │ ctid  │  xmin  │  xmax  │
    ├───┼────┼───────┼────────┼────────┤
    │ 1 │ 11 │ (0,2) │ 102508 │ 102508 │
    │ 2 │ 22 │ (0,3) │ 102508 │      0 │
    └───┴────┴───────┴────────┴────────┘
    (2 rows)
    
    SELECT lp, lp_off, t_xmin, t_xmax, t_ctid,
           to_hex(t_infomask) AS t_infomask, to_hex(t_infomask2) AS t_infomask2
    FROM heap_page_items(get_raw_page('laurenz.t', 0));
    
    ┌────┬────────┬────────┬────────┬────────┬────────────┬─────────────┐
    │ lp │ lp_off │ t_xmin │ t_xmax │ t_ctid │ t_infomask │ t_infomask2 │
    ├────┼────────┼────────┼────────┼────────┼────────────┼─────────────┤
    │  1 │   8160 │ 102507 │ 102508 │ (0,2)  │ 500        │ 4002        │
    │  2 │   8128 │ 102508 │ 102508 │ (0,2)  │ 2190       │ 8002        │
    │  3 │   8096 │ 102508 │      0 │ (0,3)  │ 900        │ 2           │
    └────┴────────┴────────┴────────┴────────┴────────────┴─────────────┘
    (3 rows)
    

    t_infomaskの意味 およびt_infomask2 src/include/access/htup_details.hにあります 。 lp_off ページ内のタプルデータのオフセットであり、t_ctid 現在のタプルID これは、ページ番号とページ内のタプル番号で構成されます。テーブルが新しく作成されたため、すべてのデータはページ0にあります。

    heap_page_itemsによって返される3つの行について説明します 。

    1. ラインポインタlp )1古い更新されたタプルが見つかります。元々はctid = (0,1)でした 、ただし、更新中に現在のバージョンのタプルIDを含むように変更されました。タプルはトランザクション102507によって作成され、トランザクション102508(INSERT ... ON CONFLICTを発行したトランザクション)によって無効化されました。 )。このタプルは表示されなくなり、VACUUM中に削除されます 。

      t_infomask 両方のxmin およびxmax コミットされたトランザクションに属し、その結果、タプルがいつ作成および削除されたかを示します。 t_infomask2 タプルがHOTで更新されたことを示します(ヒープのみのタプル )update。これは、更新されたタプルが元のタプルと同じページにあり、インデックス付きの列が変更されていないことを意味します(src/backend/access/heap/README.HOTを参照)。 。

    2. 行ポインタ2に、トランザクションINSERT ... ON CONFLICTによって作成された新しい更新されたタプルが表示されます。 (トランザクション102508)。

      t_infomask このタプルが更新の結果であることを示していますxmin は有効であり、xmax KEY SHAREが含まれています 行ロック(トランザクションが完了したため、これは関係ありません)。この行ロックは、INSERT ... ON CONFLICT中に取得されました。 処理。 t_infomask2 これがHOTタプルであることを示しています。

    3. 行ポインタ3に、新しく挿入された行が表示されます。

      t_infomask xminであることを示しています 有効であり、xmax 無効です。 xmax この値は常に新しく挿入されたタプルに使用されるため、は0に設定されます。

    したがって、ゼロ以外のxmax 更新された行のは、行ロックによって引き起こされた実装アーティファクトです。 INSERT ... ON CONFLICTが考えられます この動作が変わるように、ある日再実装されますが、それはありそうもないと思います。




    1. OracleVirtualBoxのインストール手順

    2. Ubuntu20.04にZabbixをインストールして設定する方法

    3. Androidコンテンツプロバイダーに見つからないコンテンツプロバイダーのURLを修正するにはどうすればよいですか?

    4. 一貫性のない列数のインポートのためのSSISタスク?