コピペコードで快適生活

明日使えるソースを自分のために

PostgreSQLでプロセスとロック状況を確認する

## 実行中のSQLを確認する。
SELECT * FROM pg_stat_activity;

## 実行中のSQLを確認する
## スロークエリとか主に見る分だけ
SELECT pid, query_start, substr(query, 0, 80) AS query FROM pg_stat_activity WHERE state='active' ORDER BY query_start;

## ロック状況の確認
SELECT l.pid, db.datname, c.relname, l.locktype, l.mode
FROM pg_locks l
LEFT JOIN pg_class c ON l.relation=c.relfilenode
LEFT JOIN pg_database db ON l.database = db.oid
ORDER BY l.pid;

## AccessExclusiveLockロックがかかっているか
SELECT l.pid, db.datname, c.relname, l.locktype, l.mode
FROM pg_locks l
LEFT JOIN pg_class c ON l.relation=c.relfilenode
LEFT JOIN pg_database db ON l.database = db.oid
WHERE l.mode = 'AccessExclusiveLock'
ORDER BY l.pid;

## Railsのマイグレーションでロックをかけない呪文
## デフォだとSELECTも通さないAccessExclusiveLockがかかる
class AddStatusToUsers < ActiveRecord::Migration
  disable_ddl_transaction!

  def up
    # 略
    Users.find_each do |user|
      user.update_columns(status: 'xxx')
    end
  end

  def down
    # 略
  end
end

## インデックス追加中にロックかけない
## (concurrentlyオプションを有効にする)
## https://thoughtbot.com/blog/how-to-create-postgres-indexes-concurrently-in
class AddIndexToAsksActive < ActiveRecord::Migration
  disable_ddl_transaction!

  def change
    add_index :asks, :active, algorithm: :concurrently
  end
end

メモ

PostgreSQL×Rails環境でのマイグレーションで、バカでかいテーブルに対して、add_column + eachまわしてupdate ということをやると、こうなる。

・add_columnsで、AccessExclusiveLockかかる。
・AccessExclusiveLockの中でeachでUPDATE走る。
・AccessExclusiveLockはSELECTも通さないロックなので、
 該当テーブルに対するSELECTがすべて待ちになる。
・待ちのSELECTでDBプロセス食い尽くす。
・DBが応答なくなる。
・障害発生 :unko: