[pgsql-jp: 38302] Re: SYNONYM 代わりのVIEW+RULEへの、更新時ロックの挙動について
松原 健二
matsubk @ alpha.co.jp
2007年 4月 11日 (水) 15:33:54 JST
松原です。
SAIMI Kohei 様<qs2007 @ aim.com> wrote:
> アイソレーションがread committedならば、transaction Aをコミットするまで、
> statusは0に見えますよね。で、レコードがアンロックされたあとに、前述のルー
> ルに従って更新しているということでは?
RULEによるVIEWへの更新実行は、実は内部で
1) 更新対象VIEWデータの読み取り
2) INSTEAD指定したテーブルへの、更新実行
の2手順に分かれていて、
read committed の場合、行の更新によって処理にWAITがかかるのは
2) の処理だけであるため、1)はアンロックされる前に実行されているため
OLD.* として、その時点での「id = 0, status = 0 なデータ」が読み取られる。
そしてアンロック後、OLD.id (=0) を条件とする更新が実行されてしまう、
という認識でよろしいでしょうか(※)。
> CREATE RULE upd_test
> AS ON UPDATE TO test_view
> DO INSTEAD UPDATE test_parent
> SET status = NEW.status, id = NEW.id
> WHERE id = OLD.id AND status = OLD.status;
>
> としておけば、実際にUPDATEするときにはstatusの値が変更されているので、更
> 新されないのではという想像です。
>
> #ここまで全く検証せずに書いてます。あしからず。
>
> --
> SAIMI Kohei <qs2007 @ aim.com>
>
上記(idとstatusを両方指定する)RULEを試してみたところ、
SAIMI様のご想定どおり、「status が別トランザクションによって更新された
データは、更新対象にしない」という挙動となりました。
ありがとうございます。
しかし、別な問題が起こります。
上記の(idとstatusを両方指定する)RULEにて、今度はid だけをWHERE句指定する
SQLを発行すると、
≪transaction A≫
1) DB=# BEGIN;
BEGIN
3) DB=# UPDATE test_view SET status = 1
DB-# WHERE id = 0;
UPDATE 1
5) DB=# COMMIT;
COMMIT
≪transaction B≫
2) DB=# BEGIN;
BEGIN
4) DB=# UPDATE test_view SET status = 2
DB-# WHERE id = 0; -- <5)が終わるまでWAIT
UPDATE 0 --<UPDATE 1 であることを期待
と、「idをWHERE句で指定していないのだから、statusが変更されているか
いないかに関わらず更新して欲しい」状況の場合に、更新してくれなく
なります。
(※)における私の認識が正しいのであれば、こうなってしまう理由は
理解できるのですが。。
目指している地点は、SYNONYMの完全な代替であり、
・id だけWHERE句指定すれば、status に関わらず更新してくれる
・id と status をWHERE句指定すれば、他トランザクションでstatusが更新された
場合、更新されない
という挙動となって欲しいのですが、うまい手を思いつきません。
#前回記述では、要望が不明瞭でした。申し訳ありません。
何か良い手段はありますでしょうか。
以上、よろしくお願いいたします。
=======================
(株)アルファシステムズ
第二事業本部 第二事業部 第一技術部 四課一係
松原 健二
=======================
pgsql-jp メーリングリストの案内