runlot

ステートメントの時間制限

1 文に 10 秒の上限があります。超えると 57014 で打ち切られ、この値は引き上げられません。

プロジェクトのデータベースは 1 文につき 10 秒 の上限を設けます。超えるとその文が次のエラーで打ち切られます。

[57014] canceling statement due to statement timeout

なぜあるのか

プロジェクトのデータベースはワーカーと同じプロセス内で 単一レーン で実行されます。1 文が長く走ると、そのプロジェクトへの他のリクエストがすべて後ろで待ちます。上限はその待ち時間を 10 秒に抑えます。

show statement_timeout は 0 です

この上限は PostgreSQL の statement_timeout 設定ではなく、ランタイムが別に持つ天井です。そのため SHOW statement_timeout0 を返し、SET statement_timeout で引き上げることはできません。引き下げは可能です — セッションに短い statement_timeout を置けばそちらが先に効きます。

エラーコードが同じ 57014 なので、コードでは区別できません。10 秒付近で切れたなら、この天井です。

当たったら

文を分割してください。大きな UPDATE はキー範囲で区切って複数回実行し、大量の INSERT は 1,000 行前後に区切って セッション 1 つのトランザクションに入れます。

// 12,000 件の best_rank 再計算 — 1 文だと 10 秒を超える
for (let offset = 0; ; offset += 2000) {
  const ids = await env.db.exec("select id from places order by id limit 2000 offset $1", [offset]);
  if (ids.length === 0) break;
  await env.db.exec(
    `update places p set best_rank = b.min_rank
       from (select place_id, min(rank) as min_rank from rankings
              where place_id = any($1) group by place_id) b
      where b.place_id = p.id`,
    [ids.map((r) => r.id)],
  );
}

空のテーブルで通ったマイグレーションが、データが入った後に同じ文で引っかかることがあります。相関サブクエリの UPDATE が典型です — 集約を一度行ってから結合すれば、たいてい上限内に収まります。

項目
1 文の上限10 秒
SQLSTATE57014
引き上げ不可
引き下げ可 (SET statement_timeout)

このページの目次