テック技報最新号へ →
コード

Postgres: ALTER TABLE は lock_timeout を付けて短く失敗させ、リトライする

ALTER TABLE が長いクエリの終わりを待っている間、後から来た普通の SELECT や UPDATE まで全部その後ろに並んで止まる。SET lock_timeout で数秒で諦めさせ、ループでやり直す。

@amitsinha__07 · 投稿 2026-11-01
#postgres#migration#infra

何が起きるか

ALTER TABLE orders ADD COLUMN ... のような DDL は、テーブルに最も強い ACCESS EXCLUSIVE ロックを取る。列の追加そのものは一瞬で終わる場合でも、ロックを取るまでが問題になる。

  1. 分析用の長い SELECT や、閉じ忘れのトランザクションが orders を読んでいる。
  2. ALTER TABLE が来て、そのクエリが終わるのを待つ(ロック待ち)。
  3. その後に来た普通のクエリも、待っている ALTER と競合するので、ALTER の後ろに並ぶ。
  4. 結果として、orders を触るすべてのリクエストが止まり、接続プールが埋まって本番が固まる。

「マイグレーションは一瞬で終わるはず」と思っていても、ロック待ちの行列で数秒〜数分の障害になる。

やり方

sql
SET lock_timeout = '5s';
ALTER TABLE orders ADD COLUMN note text;
  • ロックが 5 秒で取れなければ ALTER はエラーで終わり、並んでいたクエリはすぐ流れ出す。
  • 失敗したら少し待ってやり直す。マイグレーションツール側やシェルで、数回のリトライを組む。
bash
for i in 1 2 3 4 5; do
  psql "$DATABASE_URL" -v ON_ERROR_STOP=1 \
    -c "SET lock_timeout = '5s'; ALTER TABLE orders ADD COLUMN note text;" && break
  echo "lock timeout, retry $i"; sleep 10
done

注意点

出典

X の元の投稿を開く