- データベース
statement timeoutの直し方|PostgreSQL
ERROR: canceling statement due to statement timeout は、1つの SQL の実行時間が、statement_timeout の設定を超えたので、PostgreSQL が SQL を取り消したときのエラーです。 SQLSTATE は 57014 です。
直す前に、次の2つを確かめます。
| 確かめること | 方法 | 分かること |
|---|---|---|
| ① 設定はどこで決まっているか | SELECT setting, source FROM pg_settings WHERE name = 'statement_timeout' |
ロール・DB・接続・SQL のどこで設定されたか |
| ② SQL が遅いのか、ロックを待っていたのか | エラーの CONTEXT、pg_stat_activity の wait_event_type |
遅いなら SQL を速く、ロック待ちなら止めている相手を探す |
タイムアウトの値を延ばすのは、最後の手段です。ロック待ちが原因なら、延ばしても待つ時間が長くなるだけです。
確認環境:PostgreSQL 16.15、psycopg 3.3.6 で再現しました(確認日 2026年10月11日)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「statement timeoutの直し方|PostgreSQL」
再現
SHOW statement_timeout; -- 2s
SELECT pg_sleep(3);
ERROR: 57014: canceling statement due to statement timeout
Python(psycopg 3)では、psycopg.errors.QueryCanceled(sqlstate 57014)として受け取れました。公式ドキュメントによると、statement_timeout は単位を書かなければミリ秒で、0(既定)なら無効です。
① 設定がどこで決まっているかを探す
「設定した覚えがないのにタイムアウトする」ときは、pg_settings の source 列を見ます。
SELECT name, setting, unit, source FROM pg_settings
WHERE name IN ('statement_timeout', 'lock_timeout', 'idle_in_transaction_session_timeout');
| 設定のしかた | 確認環境での source |
|---|---|
ALTER ROLE tx SET statement_timeout = '2s' |
user |
ALTER DATABASE reldemo SET statement_timeout = '4s' |
database |
接続のときに指定(PGOPTIONS="-c statement_timeout=1500"、接続文字列の options) |
client |
接続してから SET statement_timeout = '5s' |
session |
| 何も設定していない | default(0) |
ロールと DB の両方に設定したときは、ロールの設定(2s)が使われ、source は user でした。 ロール・DB に付けた設定の一覧は、次の SQL で見られます。
SELECT r.rolname, d.datname, s.setconfig
FROM pg_db_role_setting s
LEFT JOIN pg_roles r ON r.oid = s.setrole
LEFT JOIN pg_database d ON d.oid = s.setdatabase;
rolname | datname | setconfig
---------+---------+------------------------
tx | | {statement_timeout=2s}
公式ドキュメントでは、statement_timeout を postgresql.conf に書くことは、すべてのセッションに影響するため推奨しないとされています。アプリのフレームワーク・接続プールの設定(接続文字列の options など)で付いていることもあるので、client と表示されたらアプリの設定を探します。
② 遅い SQL か、ロック待ちかを見分ける
別の接続で行を UPDATE したまま(トランザクションを閉じずに)、同じ行を UPDATE しました。
ERROR: 57014: canceling statement due to statement timeout
CONTEXT: while updating tuple (0,6) in relation "st_acc"
CONTEXT: while updating tuple ... in relation "st_acc" が付いていたら、行のロックを待っている間にタイムアウトしたと読めます。pg_sleep だけの遅い SQL では、CONTEXT は付きませんでした。
止めている相手を pg_stat_activity で探す
SELECT pid, application_name AS app, state, wait_event_type AS wtype, wait_event,
pg_blocking_pids(pid) AS blocked_by, left(query, 40) AS query
FROM pg_stat_activity
WHERE datname = 'reldemo' AND pid <> pg_backend_pid();
pid | app | state | wtype | wait_event | blocked_by
------+---------+--------+---------+---------------+------------
1841 | batch_a | active | Timeout | PgSleep | {}
1845 | web_b | active | Lock | transactionid | {1841}
| 列 | 読み方 |
|---|---|
wait_event_type = Lock |
ロックを待っている(web_b) |
blocked_by = {1841} |
pid 1841(batch_a)に止められている |
wait_event_type が空 |
待たずに動いている(SQL そのものが遅い) |
ロック待ちが原因なら、直すのは止めている側(batch_a)です。長いトランザクションを短くする、ロックを取る順番をそろえる、などを検討します。application_name を接続ごとに付けておくと、どのプログラムかが分かります。
lock_timeout との違い
lock_timeout = '1s' を付けて、同じロック待ちを起こしました。
ERROR: 55P03: canceling statement due to lock timeout
CONTEXT: while updating tuple (0,6) in relation "st_acc"
| 設定 | 何を測るか | エラー | SQLSTATE |
|---|---|---|---|
| statement_timeout | SQL 全体の時間 | canceling statement due to statement timeout |
57014 |
| lock_timeout | ロックを待つ時間だけ | canceling statement due to lock timeout |
55P03 |
| idle_in_transaction_session_timeout | トランザクションの中で何もしない時間 | セッションが切られる | ― |
公式ドキュメントでは、statement_timeout が 0 でないとき、lock_timeout を同じか大きい値にしても意味がない(先に statement_timeout が来るため)と説明されています。lock_timeout を短め、statement_timeout を長めにすると、エラーの種類で原因を見分けられます。
idle_in_transaction_session_timeout は、トランザクションを開いたまま放置する接続を切ります。 公式ドキュメントでも、ロックを長く持ち続けるのを防ぐ用途が挙げられています。上の batch_a のような接続への対策になります。
一部の処理だけ、タイムアウトを延ばす(SET LOCAL)
夜間の集計だけ長くしたい、といった場合は、トランザクションの中で SET LOCAL を使います。
BEGIN;
SET LOCAL statement_timeout = '30min'; -- このトランザクションの中だけ
-- 時間のかかる集計
COMMIT;
SHOW statement_timeout; -- 元の値に戻っている
| 確認環境での動き | 結果 |
|---|---|
SET LOCAL statement_timeout = '1s' のあと pg_sleep(2) |
タイムアウト。ROLLBACK 後は元の 5s に戻った |
SET LOCAL statement_timeout = 0 のあと pg_sleep(6) |
成功。COMMIT 後は元の 5s に戻った |
トランザクションの外で SET LOCAL |
WARNING: SET LOCAL can only be used in transaction blocks、値は変わらない |
SET(LOCAL なし)は、その接続を使い続ける限り残ります。 接続プールでは、次にその接続を使う別の処理にも影響するので、SET LOCAL を使います。
遅い SQL を速くする
ロック待ちでなかった場合は、SQL そのものを見直します。
| 確かめること | 方法 |
|---|---|
| 実行計画 | EXPLAIN (ANALYZE, BUFFERS) SQL |
| 索引が使われているか | 実行計画の Seq Scan |
| 一度に扱う行が多すぎないか | 小分け(1万件ずつなど) |
確認の手順(チェックリスト)
| 順番 | 確認すること | 方法 |
|---|---|---|
| 1 | 設定の値と出どころ | pg_settings の setting・source |
| 2 | ロール・DB の設定 | pg_db_role_setting |
| 3 | ロック待ちか | CONTEXT: while updating tuple、wait_event_type = Lock |
| 4 | 止めている相手 | pg_blocking_pids(pid) |
| 5 | 遅い SQL なら | EXPLAIN (ANALYZE, BUFFERS) |
| 6 | 延ばすなら | SET LOCAL で、その処理だけ |
よくある質問
Q. デッドロックのエラーとは違いますか。 A. 違います。デッドロックは、お互いが相手を待つ状態を PostgreSQL が見つけて、片方を止めるエラーです。タイムアウトは、待つ時間(実行時間)が設定を超えたときのエラーです。MySQL のデッドロックは、関連記事の「MySQL Deadlock foundの原因と対処|1213・1205」で扱っています。
まとめ
- SQL の実行時間が statement_timeout を超えたエラー(57014)
pg_settingsのsourceで、ロール・DB・接続・SQL のどこで設定されたかが分かるCONTEXT: while updating tupleはロック待ち。pg_blocking_pidsで止めている相手を探す- lock_timeout(55P03)を短めにすると、原因を見分けやすい
- 延ばすなら
SET LOCAL(トランザクションの外では効かない)
参考・出典
確認日はいずれも 2026年10月11日です。
- PostgreSQL 16 文書「Client Connection Defaults」(statement_timeout・lock_timeout):https://www.postgresql.org/docs/16/runtime-config-client.html
- PostgreSQL 16 文書「SET」:https://www.postgresql.org/docs/16/sql-set.html
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「statement timeoutの直し方|PostgreSQL」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。