PostgreSQL · 错误码速查
PostgreSQL canceling statement due to statement timeout:先查超时从哪来,再查为什么慢
语句从到达服务器起算,执行时间超过 statement_timeout 就会被取消,报 ERROR: canceling statement due to statement timeout,SQLSTATE 57014。它只说明「超时了」,不说明为什么慢:可能是计划不对、在等锁、或资源不够。先查这个超时值是谁设的(会话、角色、数据库、连接串),再用 auto_explain 或带同样参数的 EXPLAIN (ANALYZE, BUFFERS) 查慢在哪;不要第一步就把超时调大。
官方原文
canceling statement due to statement timeout出自 PostgreSQL 源码 src/backend/tcop/postgres.c 的 ProcessInterrupts(),错误码 ERRCODE_QUERY_CANCELED(errcodes.txt 中为 57014 query_canceled)。参数文档原文:statement_timeout「Abort any statement that takes more than the specified amount of time」,从命令到达服务器开始计时。
出处:PostgreSQL 源码 REL_17_STABLE:src/backend/tcop/postgres.c(ProcessInterrupts) 最后核对:
| SQLSTATE | 57014(query_canceled) | 出处 |
|---|---|---|
| 计时起点 | 命令到达服务器起算到服务器完成;扩展协议下从 Parse/Bind/Execute/Describe 任一消息到达开始 | 出处 |
| 默认值 | 0,即不限制;官方不建议写进 postgresql.conf,因为会影响所有会话 | 出处 |
| 同码不同因 | pg_cancel_backend() 或客户端取消同样是 57014,原文是 canceling statement due to user request | 出处 |
| 相邻报错 | canceling statement due to lock timeout 是 55P03(lock_not_available),只在等锁时触发 | 出处 |
盈尺实测(测试库,非官方文档):同一条 SQL 普通参数约 1ms、某个参数 650–894ms;statement_timeout=300ms 时被取消的那次 auto_explain 不记计划,跑完的那次记下 666.035 ms 和完整计划。测试库自造数据。 PostgreSQL 查询偶发变慢:用 auto_explain 把慢的那一次执行计划抓下来(PG 17.11 测试库实测) →
测试库上的实际输出:三种「canceling statement」长得很像
2026-11-06 在 box 本机 PostgreSQL 17.11 测试库(自造数据)用 \set VERBOSITY verbose 逐一触发,三条报错开头一样,SQLSTATE 和含义不同:
| 触发方式 | 客户端看到的原文 | SQLSTATE |
|---|---|---|
SET statement_timeout='200ms'; SELECT pg_sleep(1); | canceling statement due to statement timeout | 57014 |
另一会话 LOCK orders IN ACCESS EXCLUSIVE MODE,本会话 SET lock_timeout='300ms' 后查 orders | canceling statement due to lock timeout | 55P03 |
同样等锁,但只设 statement_timeout='300ms' | canceling statement due to statement timeout | 57014 |
另一会话 SELECT pg_cancel_backend(pid) | canceling statement due to user request | 57014 |
第三行最容易误判:语句其实一直在等锁,但只设了 statement_timeout,报出来是「statement timeout」。所以看到 57014 不能直接下结论「SQL 太慢」,要先排除等锁。
在显式事务(BEGIN)里超时后,事务进入失败状态,后续语句会报 25P02: current transaction is aborted, commands ignored until end of transaction block,必须 ROLLBACK。测试库上 BEGIN; SET LOCAL statement_timeout='200ms'; SELECT pg_sleep(1); SELECT 1; 就是这个结果。
先查超时是谁设的:会话、角色、数据库还是连接串
同一个库,有的连接超时有的不超时,通常是超时值来自不同层级。下面都是只读查询:
SHOW statement_timeout; -- 当前会话实际生效值
SELECT name, setting, source FROM pg_settings
WHERE name IN ('statement_timeout','lock_timeout','transaction_timeout','idle_in_transaction_session_timeout');
-- 角色级 / 数据库级设置(ALTER ROLE ... SET / ALTER DATABASE ... SET)
SELECT coalesce(r.rolname,'(所有角色)') AS role, coalesce(d.datname,'(所有库)') AS db, 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;- 测试库验证:
ALTER ROLE app_ro SET statement_timeout='150ms'后,用 app_ro 新登录SHOW statement_timeout返回 150ms,SELECT pg_sleep(0.5)报 57014;用 postgres 登录不受影响。 - 连接串和驱动也能设:libpq 的
options='-c statement_timeout=5000'、JDBC 的options参数、连接池(如 PgBouncer)的连接初始化语句,都会在会话层覆盖。 - PostgreSQL 17 新增
transaction_timeout;它比 statement_timeout 短或相等时,较长的那个会被忽略。
再查为什么慢:超时取消的语句,auto_explain 不记计划
直觉做法是开 auto_explain 等它记录,但测试库实测:statement_timeout=300ms 时被取消的那次,日志里只有 ERROR 和 STATEMENT 两行,没有计划;RESET 后同一条 SQL 跑完(666.035 ms),auto_explain 才记下完整计划。auto_explain 只在语句正常结束时输出。
- 把
auto_explain.log_min_duration设得明显小于 statement_timeout(例如超时 2s、阈值 500ms),抓「慢但还没超时」的那些执行。 - 日志里 STATEMENT 行给出的是原始 SQL;走扩展协议时参数值不在这一行,用 auto_explain 的 Query Parameters(PG16+)或应用日志补上。
- 拿到慢参数后,在测试环境用同一参数跑
EXPLAIN (ANALYZE, BUFFERS);先看是不是在等锁(pg_stat_activity.wait_event_type = 'Lock'),再看计划。完整例子见《PostgreSQL 查询偶发变慢:用 auto_explain 把慢的那一次抓下来》。
超时怎么设才合理:按角色设,不要全局写死
官方文档明确不建议在 postgresql.conf 里设 statement_timeout,因为会影响所有会话(包括备份、迁移、VACUUM 脚本)。更稳妥的做法:
ALTER ROLE app_web SET statement_timeout = '5s'; -- 在线接口用户
ALTER ROLE app_report SET statement_timeout = '5min'; -- 报表用户
-- 迁移 / 大批量任务在会话里临时放开
SET statement_timeout = 0;
-- 等锁单独设得更短,避免 DDL 排队拖垮业务
SET lock_timeout = '3s';- lock_timeout 要小于 statement_timeout,否则(官方原话)设了也基本没意义,因为 statement_timeout 总会先触发。
- 把超时调大前先确认慢的原因;如果是计划问题,调大超时只是把 5 秒的报错变成 50 秒的卡顿。
常见问题
canceling statement due to statement timeout 是什么意思?
语句执行时间超过了 statement_timeout,被服务器取消,SQLSTATE 57014。它不说明为什么慢,需要再查计划或锁等待。
statement timeout 和 lock timeout 有什么区别?
statement_timeout 限制整条语句的执行时间,报 57014;lock_timeout 只限制单次等锁时间,报 55P03 canceling statement due to lock timeout。只设了 statement_timeout 时,等锁超时也会报 statement timeout。
为什么只有部分连接报 57014?
超时值可能来自角色级、数据库级或连接串设置。用 SHOW statement_timeout 和 pg_settings.source、pg_db_role_setting 查实际来源。
超时后为什么后面的 SQL 都报 current transaction is aborted?
在显式事务里,任何语句出错都会让事务进入失败状态,后续语句报 25P02,必须先 ROLLBACK。
开了 auto_explain 为什么抓不到超时那条 SQL 的计划?
被取消的语句不会被 auto_explain 记录。把 log_min_duration 设得比 statement_timeout 小,抓那些慢但还没超时的执行。
免费 · 留邮箱领检查单
PostgreSQL 14 停更升级检查单(Excel 可直接打开)
- PG14 2026-11-12 停更,升 17 / 18 前后 19 项检查:只读预检、--check、回滚、补统计、回归
- 每项写清怎么查、通过标准、不处理会怎样(附测试库实测数字)
- 配合站上的只读预检 SQL 使用,每个业务库各跑一次
下一步
价格以对应页面当前标价为准。
出处(最后核对 2026-11-06)
- PostgreSQL 源码 REL_17_STABLE:src/backend/tcop/postgres.c(ProcessInterrupts)
- PostgreSQL 17 文档 附录 A:PostgreSQL Error Codes(57014 query_canceled、55P03 lock_not_available)
- PostgreSQL 17 文档 19.11:Client Connection Defaults(statement_timeout、lock_timeout、transaction_timeout)
- PostgreSQL 17 文档 F.3:auto_explain
本页摘录并解读上面列出的官方文档,不是官方页面;官方文档更新后以官方为准。除标明「盈尺实测」的一段外,其余内容都来自官方文档。