2010年2月16日

[pgsql-jp: 40175] Re:update文のフリーズ

石井です。

> 2010/2/16 Eiichiro Sakai <sakai@xxxxx>:
> > 以下のようなSQLをpgpool2(2.1)経由で複数のプロセスより大量に実行していたと
> > ころupdate文(下記tr2)が途中でフリーズし、その後同様のSQLを実行しても
> > select for update文(下記tr1)がロック待ちの状態となり滞留し続けていく状況と
> > なりました。
> >

> > begin;
> > select * from tableA where id = 1;(tr1)
> > その他の処理
> > update tableA SET column = xx where id = 1;(tr2)
> > commit;
> >
> > 1.トリガとなったupdate文のSQLログを見るとbindまでは出力されていますが、
> > executeのログが出力されていない状況で止まってしまっています。
> > これはどのような時に発生しうるでしょうか?
> > 回避策をご存じの方がいらっしゃればご教授いただければと思います。
>
> 文中の SQL ログとはどのログ (PostgreSQL のサーバログ? pgpool? アプリ独自?) を
> 指しますでしょうか?
>
> 可能であれば、そのログをいただけませんでしょうか?
>
> execute message は PostgreSQL には届いていないとの認識でよろしいでしょうか?
> この認識で正しければ、問題の UPDATE の前に実行された SELECT FOR UPDATE が
> ロックを獲得したままになっています。このロックは COMMIT / ROLLBACK の段階で
> 開放されますが、UPDATE の execute message が届かないため、そこまで処理が
> 進みません。このため、他の SELECT FOR UPDATE がロック待ちになったのだと思われます。
>
> まずは、execute message がどこまで届いたのか確認してください。PostgreSQL まで
> 届いていなければ、上記の通りで、pgpool またはアプリ側の問題を次に疑います。

ログがSQLのログだとして...

executeのログが表示されないのは、executeがロック待ちで実行されていない
状態もあり得ます。今回はその可能性もあるのではないでしょうか。

もし、tr1とtr2が本当に同じセッションだとし、かつselect for updateと
updteのwhere句が同じなのに、tr1は実行できていてtr2が実行されない、とい
うのはかなりあり得ない状況のように思えます。かろうじて近いのは、最近
hackersに投稿された、ケースですが、これに当てはまるかどうか、良く分か
りません。詳しいログを見る必要がありますね。

ログにpidやセッションidが出力されていることを確認し、同一トランザクショ
ン内で上記のような現象が起きているかどうか確認した方がよいと思います。

> > 2.tr2でフリーズ後のpg_stat_activityを見るとフリーズが起こる前に実行されて
> > い
> > るがtr1でロック待ちのままとなっているトランザクションが多数存在していま
> > した。
> > ただ、フリーズが起こる前は他のいくつかのトランザクションは正常終了(上記
> > commitまで終了)している状態です。
> > このことよりpostgresは必ずしもロック要求があった順番にロック取得
> > しているわけではないように思えますが理解は正しいでしょうか?
>
> はい。アプリが発行した順序でクエリが実行されるとは限りません。OS のスケジューラ等の
> 都合によって、クエリの実行順序は前後します。

元の質問の意図は、「同じトランザクション(セッション)内で」という前提の
話ではないでしょうか。であれば、必ず発行した順にロックが取られます。
--
Tatsuo Ishii
SRA OSS, Inc. Japan
English: http://www.sraoss.co.jp/index_en.php
Japanese: http://www.sraoss.co.jp


投稿者 xml-rpc : 2010年2月16日 22:45
役に立ちました?:
過去のフィードバック 平均:(0) 総合:(0) 投票回数:(0)
本記事へのTrackback: http://hoop.euqset.org/blog/mt-tb2006.cgi/93367
トラックバック
コメント
コメントする




画像の中に見える文字を入力してください。