この記事は PostgreSQL Advent Calendar 2025 の22日目です。
タイムアウトとは一定時間内に応答のない処理をキャンセルすることです。PostgreSQLにもいろいろなタイムアウト設定があります。この記事では接続とクエリ実行に関する設定について紹介します。
下記はPostgreSQLでタイムアウト設定が可能な処理で、カッコ内はそのパラメータ名を表します。
各パラメータの意味は下記です。
| パラメータ名 | 説明 |
|---|---|
| connect_timeout | 接続のタイムアウト時間。秒単位。デフォルトは0 (無効)。接続パラメータなので、postgresql.confで設定不可 |
| authentication_timeout | 認証のタイムアウト時間。外部認証サービスの応答遅延を早めに切り上げるのに役立つ。デフォルトは1min (1分) |
| statement_timeout | クエリ実行のタイムアウト時間。ロック待ち時間も含む。デフォルトは0 (無効) |
| transaction_timeout | トランザクション実行のタイムアウト時間。クエリ入力待ち時間を含む。デフォルトは0 (無効)。バージョン17で追加 |
| lock_timeout | ロック待ちのタイムアウト時間。デフォルトは0 (無効)。バージョン9.3で追加 |
| idle_in_transaction_session_timeout | トランザクション内でクエリ入力待ちのタイムアウト時間。ロックを取得したままのトランザクションのキャンセルに役立つ。デフォルトは0 (無効)。バージョン9.6で追加 |
| idle_session_timeout | クエリ入力待ちのタイムアウト時間。未使用の接続を切断するのに役立つが、外部コネクションプール使用時は影響に注意。デフォルトは0 (無効)。バージョン14で追加 |
まず、タイムアウトの設定方法についてです。
connect_timeoutは接続パラメータなので、postgresql.confで設定するのでなく、psqlであれば下記のように 接続文字列 で指定します。
$ psql -d "dbname=db1 connect_timeout=10"
psql (17.7)
"help"でヘルプを表示します。
db1=#
connect_timeout以外はpostgresql.confやSETなどで設定できますが、前者だと、全セッションに影響するので、注意してください。
#authentication_timeout = 1min # 1s-600s
(省略)
#statement_timeout = 0 # in milliseconds, 0 is disabled
#transaction_timeout = 0 # in milliseconds, 0 is disabled
#lock_timeout = 0 # in milliseconds, 0 is disabled
#idle_in_transaction_session_timeout = 0 # in milliseconds, 0 is disabled
#idle_session_timeout = 0 # in milliseconds, 0 is disabled
次に、タイムアウトの動作確認をしていきます。
接続と認証はタイムアウトを発生させるのが難しいので、connect_timeoutとauthorizatoin_timeoutの動作確認はスキップします。
クエリ実行のタイムアウトを確認します。statement_timeoutを5秒に設定し、pg_sleep関数で10秒のスリープを開始し、5秒経過すると、クエリがキャンセルされます。
db1=# SET statement_timeout TO '5s';
SET
db1=# SELECT pg_sleep(10);
(5秒経過)
ERROR: canceling statement due to statement timeout
トランザクション内でのクエリ入力待ちのタイムアウトを確認します。idle_in_transaction_session_timeoutを5秒に設定し、トランザクションを開始し、5秒経過すると、接続が切断されます。切断はクエリ実行時に検出され、その際、再接続され、SETで設定したstatement_timeoutとidle_in_transaction_session_timeoutもリセットされます。
db1=# SET idle_in_transaction_session_timeout TO '5s';
SET
db1=# BEGIN;
BEGIN
db1=#
(5秒経過)
db1=*# SELECT 1;
FATAL: terminating connection due to idle-in-transaction timeout
サーバーとの接続が想定外にクローズされました
おそらく要求の処理前または処理中にサーバーが異常終了
したことを意味しています。
サーバーへの接続が失われました。リセットしています: 成功。
トランザクション実行のタイムアウトを確認します。transaction_timeoutを10秒に設定し、トランザクションを開始し、クエリが実行中か入力待ちかに関係なく、10秒経過すると、トランザクションがキャンセルされ、接続が切断されます。BEGINで明示的にトランザクションを開始していない場合、1つ1つのクエリがトランザクションとして扱われます。
db1=# SET transaction_timeout TO '10s';
SET
db1=# BEGIN;
BEGIN
db1=*# SELECT 1;
?column?
----------
1
(1 行)
db1=*# SELECT 1;
?column?
----------
1
(1 行)
(10秒経過)
db1=*# SELECT 1;
FATAL: terminating connection due to transaction timeout
サーバーとの接続が想定外にクローズされました
おそらく要求の処理前または処理中にサーバーが異常終了
したことを意味しています。
サーバーへの接続が失われました。リセットしています: 成功。
ロック待ちのタイムアウトを確認します。別の端末でトランザクションを開始し、テーブルt1のロックを取得した状態で、元の端末でlock_timeoutを5秒に設定し、トランザクションを開始し、テーブルt1のロックを取得しようとすると、ロック待ちで応答がなく、5秒経過すると、クエリがキャンセルされます。
(別の端末で実行)
$ psql db1
psql (17.7)
"help"でヘルプを表示します。
db1=# BEGIN;
BEGIN
db1=*# LOCK t1;
LOCK TABLE
db1=*#
(元の端末で実行)
db1=# SET lock_timeout TO '5s';
SET
db1=# BEGIN;
BEGIN
db1=*# LOCK t1;
(5秒経過)
ERROR: canceling statement due to lock timeout
db1=!# ROLLBACK;
ROLLBACK;
クエリ入力待ちのタイムアウトを確認します。idle_session_timeoutを5秒に設定し、何もせず、5秒が経過すると、接続が切断されます。
db1=# SET idle_session_timeout TO '5s';
SET
db1=#
(5秒経過)
db1=# SELECT 1;
FATAL: terminating connection due to idle-session timeout
サーバーとの接続が想定外にクローズされました
おそらく要求の処理前または処理中にサーバーが異常終了
したことを意味しています。
サーバーへの接続が失われました。リセットしています: 成功。
PostgreSQLにはいろいろなタイムアウト設定があり、それぞれの意味を理解した上で使い分けることが大切です。
