Errore PostgreSQL: canceling statement due to statement timeout
ERROR: canceling statement due to statement timeout
Lo statement è girato più a lungo di quanto consente statement_timeout, misurato in tempo di orologio da quando il server l'ha ricevuto — incluso qualsiasi tempo passato ad attendere lock. PostgreSQL l'ha annullato e ne ha fatto il rollback degli effetti.
Cosa significa questo errore
Lo SQLSTATE 57014 (query_canceled) copre tutte le cancellazioni di statement; il messaggio ti dice quale hai avuto:
due to statement timeout— questa pagina:statement_timeoutè scaduto.due to user request— qualcuno ha premuto Ctrl+C o ha chiamatopg_cancel_backend().due to lock timeout— un'impostazione diversa (lock_timeout) e uno SQLSTATE diverso (55P03): lo statement ha rinunciato ad aspettare un lock.
La sottigliezza che conta: statement_timeout conta anche le attese sui lock. Una query che normalmente impiega 50 ms può colpire un timeout di 30 s perché è rimasta dietro l'ALTER TABLE di qualcuno. Prima di "ottimizzare" la query, scopri in quale caso ti trovi.
Cause comuni
- Una query davvero lenta: indice mancante, un piano che è cambiato dopo la crescita dei dati o statistiche obsolete, uno scan illimitato.
- Bloccata su un lock: la query andava bene ma ha aspettato dietro del DDL o una transazione di scrittura lunga.
- Il timeout è impostato più basso di quanto pensi — globalmente in
postgresql.conf, per ruolo o database (ALTER ROLE ... SET statement_timeout), per sessione dal driver/ORM, o per transazione. Questi si sovrascrivono a vicenda ed è facile perdere il conto. - Un job batch o una migrazione che legittimamente ha bisogno di minuti, in esecuzione sotto un timeout dimensionato per OLTP.
Come diagnosticarlo
-- Da dove viene il valore attivo:
SELECT name, setting, source
FROM pg_settings
WHERE name = 'statement_timeout';
-- Override per ruolo/database:
SELECT * FROM pg_db_role_setting;
Lo statement annullato viene scritto nel log del server insieme all'errore, quindi sai esattamente quale query era. Poi separa i due casi:
- Eseguila con
EXPLAIN (ANALYZE, BUFFERS)in un contesto sicuro e guarda dove va il tempo — incolla il JSON nel visualizzatore EXPLAIN e controlla i nodi più lenti e i warning sulle stime delle righe. - Se si riproduce dal vivo, controlla
wait_event_type/wait_eventinpg_stat_activitymentre gira:Locksignifica che è un problema di blocco, non di velocità della query.
Come risolverlo
- Query lenta → correggi la query o l'indicizzazione; quella è la vera soluzione, il timeout l'ha solo fatta emergere.
- Operazione lunga legittima → restringi l'eccezione invece di alzare il valore globale:
BEGIN; SET LOCAL statement_timeout = '30min'; -- vale solo per questa transazione -- ... migrazione o report ... COMMIT; - Attese sui lock → usa
lock_timeoutper il DDL così fallisce in fretta invece di accodarsi (e bloccare tutti dietro di sé), e dai la caccia alla transazione lunga che teneva il lock. - Mantieni un limite globale sensato. Uno
statement_timeoutglobale modesto è una protezione contro le query fuori controllo; la risposta a un falso positivo è un override circoscritto, non disattivarlo.
