[pgpool-general-jp: 641] Re: pgpoolでのholdable cursorの使用について

Tatsuo Ishii ishii @ sraoss.co.jp
2009年 11月 29日 (日) 21:02:32 JST


お返事が遅くなり、申し訳ありません。

石井です。PostgreSQL Conferenceでは本当に久しぶりにお会いできて良かっ
たです。

> Hiroshi Inoue wrote:
> > はじめてお世話になります。
> > 井上です。
> > 
> > 本家のpgsql-odbcに
> > [ODBC] declare/fetch problem with pgpool 2.2.3; Postgres 8.4; ODBC
> > 8.03.04.00
> > の投稿がありました。pgpoolとODBCの組合せ利用における不具合の報告
> > ですが、pgpoolは未経験でよくわからず、お知恵をお貸しください。
> 
> JPUGConでは色々お世話になりありがとうございました。
> その場で石井さんには簡単に説明させていただきましたが、補足させて
> いただきます。まず元記事は
> http://archives.postgresql.org/pgsql-odbc/2009-11/msg00037.php
> です。
> psqlODBCドライバでは大量のデータを返すselectを使う際のメモリ使用
> の抑制や応答時間短縮のために、内部的にカーソルを利用するuse
>  declare/fetch modeを大昔から提供しています。7.4からはholdable
> カーソルを利用してトランザクションをまたぐ処理も可能となっていま
> す。use declare/fetch modeで発行されるコマンド又はメッセージは
> 下記のとおりです。
> 
> 1)オープン(round trip時間節約のためマルチコマンド呼出し)
>  [BEGIN;]declare ... cursor with hold for select ...;fetch
>    最初の何行か(デフォルトでは100行) in ....
> 
> 2)フェッチ
>   コミット前) 拡張プロトコル executeメッセージ使用
>   コミット後) FETCHコマンド使用
> 
> 3)位置移動
>   MOVEコマンド使用
> 
> 4)クローズ
>   CLOSEコマンド使用
> 
> 1)及び2)のexecuteは最初のトランザクション内で実行されますが
> 2)3)4)のFETCH,MOVE,CLOSEはトランザクション外で発行される
> 可能性があります。元記事の例ではコミット後にトランザクション
> ブロック外でCLOSEコマンドが発行されていると思われます。

この件ですが、おっしゃる通りで、カーソルを使った更新に対する考慮が抜け
ていました。対策としては、これらのコマンドをまとめて負荷分散不可にする
ことにします。次のバージョン(2.2.6)で正式対応しますが、お急ぎの方は添
付のパッチをお試し下さい。

本当はFETCH, MOVEは負荷分散OKにし、CLOSEでは、カーソルが更新可能であっ
たかどうかによって、負荷分散する/しない、を切り替えるのがベストなので
すが、これは今後の課題とさせてください。
--
Tatsuo Ishii
SRA OSS, Inc. Japan
-------------- next part --------------
Index: pool_process_query.c
===================================================================
RCS file: /cvsroot/pgpool/pgpool-II/pool_process_query.c,v
retrieving revision 1.141.2.28
retrieving revision 1.141.2.29
diff -c -r1.141.2.28 -r1.141.2.29
*** pool_process_query.c	14 Nov 2009 13:16:48 -0000	1.141.2.28
--- pool_process_query.c	29 Nov 2009 11:59:32 -0000	1.141.2.29
***************
*** 1,6 ****
  /* -*-pgsql-c-*- */
  /*
!  * $Header: /cvsroot/pgpool/pgpool-II/pool_process_query.c,v 1.141.2.28 2009/11/14 13:16:48 t-ishii Exp $
   *
   * pgpool: a language independent connection pool server for PostgreSQL
   * written by Tatsuo Ishii
--- 1,6 ----
  /* -*-pgsql-c-*- */
  /*
!  * $Header: /cvsroot/pgpool/pgpool-II/pool_process_query.c,v 1.141.2.29 2009/11/29 11:59:32 t-ishii Exp $
   *
   * pgpool: a language independent connection pool server for PostgreSQL
   * written by Tatsuo Ishii
***************
*** 2248,2258 ****
   * returns non 0 if the SQL statement can be load
   * balanced. Followings are statemnts go into this category.
   *
!  * - SELECT without FOR UPDATE/SHARE
   * - COPY TO STDOUT
-  * - DECLARE..SELECT (without INTO nor FOR UPDATE/SHARE)
-  * - FETCH
-  * - CLOSE
   *
   * note that for SELECT INTO, this function returns 0
   */
--- 2248,2255 ----
   * returns non 0 if the SQL statement can be load
   * balanced. Followings are statemnts go into this category.
   *
!  * - SELECT/WITH without FOR UPDATE/SHARE
   * - COPY TO STDOUT
   *
   * note that for SELECT INTO, this function returns 0
   */
***************
*** 2281,2306 ****
  			sql++;
  	}
  
! 	if (IsA(node, SelectStmt) || IsA(node, DeclareCursorStmt))
  	{
  		SelectStmt *select_stmt;
  
! 		if (IsA(node, SelectStmt))
! 			 select_stmt = (SelectStmt *)node;
! 		else
! 			select_stmt = (SelectStmt *)((DeclareCursorStmt *)node)->query;
  
  		if (select_stmt->intoClause || select_stmt->lockingClause)
  			return 0;
  
! 		if (IsA(node, SelectStmt))
! 			return (*sql == 's' || *sql == 'S' || *sql == '(');
! 		else
! 			return (*sql == 'd' || *sql == 'D');
! 	}
! 	else if (IsA(node, FetchStmt) || IsA(node, ClosePortalStmt))
! 	{
! 		return (*sql == 'f' || *sql == 'F' || *sql == 'c' || *sql == 'C');
  	}
  	else if (IsA(node, CopyStmt))
  	{
--- 2278,2294 ----
  			sql++;
  	}
  
! 	if (IsA(node, SelectStmt))
  	{
  		SelectStmt *select_stmt;
  
! 		select_stmt = (SelectStmt *)node;
  
  		if (select_stmt->intoClause || select_stmt->lockingClause)
  			return 0;
  
! 		return (*sql == 's' || *sql == 'S' || *sql == '(' ||
! 				*sql == 'w' || *sql == 'W' || *sql == 't' || *sql == 'T');
  	}
  	else if (IsA(node, CopyStmt))
  	{


pgpool-general-jp メーリングリストの案内