web-dev-qa-db-ja.com

書き込み可能なCTEでのスナップショットアイソレーションの回避策

Postgres docs say

WITHのサブステートメントは、相互に同時に実行され、メインクエリと同時に実行されます。したがって、WITHでデータ変更ステートメントを使用する場合、指定された更新が実際に発生する順序は予測できません。すべてのステートメントは同じスナップショット(第13章を参照)で実行されるため、ターゲットテーブルに対する互いの影響を「確認」することはできません。これは…データを返すことが、異なるWITHサブステートメントとメインクエリの間で変更を伝達する唯一の方法であることを意味します。

私はこのような状況でこの影響を回避する方法を探しています:

スキーマ設定

create table t1(id serial);

create table t2(id integer);

create function f1() returns integer language sql as $$
  insert into t1 default values returning id; --
$$;

create function f2() returns integer language sql as $$
  with w as (insert into t1 default values returning id)
  insert into t2(id) select id from w join t1 using(id) returning id; --
$$;

select f2()
/*
|     F2 |
----------
| (null) |
*/

select * from t1
/*
| ID |
------
|  1 |
*/

select * from t2
/*
| ID |
------
*/

SQLFiddle

f2insertt1のデータを表示したいので、t2の1行になります。

CTEから*を返すと、現在t1から読み取ろうとしている行を効果的に読み取っています。これにより、t1に加えた変更を読み取るように管理できます。

ちなみに、現在のコードではt1への結合は冗長ですが、実際に必要なよりも単純な例を使用しているように見えます。

1
David Aldridge