良い一日。postgresで分離レベルをいじっていたREAD COMMITTEDところ、公式ドキュメントに従わない奇妙な動作が見つかりました。テーブルaccount(id int,name text,amount int)と 2 つの行があるとします。
test> select * from account;
-[ RECORD 1 ]-------------------------
id | 1
name | Bob
amount | 800
-[ RECORD 2 ]-------------------------
id | 2
name | Bob
amount | 200
ここで、2 つの READ COMMITTED トランザクションを開始します。最初のものは次のクエリを実行します
UPDATE account set amount = 100 where id = 2; -- 1
そして、2番目はこのクエリを実行します
UPDATE account set amount = amount+50 --2
where name in
(select DISTINCT name from account group by
name having sum(amount)>=1000);
最初のトランザクションがまだコミットされていないため、現在はロックされています。したがって、2 番目のトランザクションでは、合計金額が 1000 以上の各口座に 50 を追加する必要があります。Bob には 2 つの口座 (800+200) があるため、各口座に 50 を追加する必要があります。ただし、最初のトランザクションがコミットさCOMMIT; --1れ、Bob の合計は 900 になり、Documentation Read commit transaction willによると、
コマンドの検索条件 (WHERE 句) が再評価され、更新されたバージョンの行がまだ検索条件に一致するかどうかが確認されます。その場合、2 番目の updater は、行の更新されたバージョンを使用して操作を続行します。
私の知る限り、2 番目のトランザクションは where 条件を再評価し、ボブのアカウントをスキップします。ただし、2 番目のトランザクションがコミットされると、最終的な行は次のようになります
id | 1 │
name | Bob │
amount | 850 │
-[ RECORD 3 ]------------------------- │
id | 2 │
name | Bob │
amount | 150
これは、2 番目のトランザクションが検索条件を再評価せず、条件に一致しない場合でも行に更新を適用したことを意味します。なぜそれが起こるのですか?ドキュメントで何かを見逃していましたか?