psqlの\watchでクエリを繰り返し実行する
psqlの\watchメタコマンドは、直前に実行したクエリを一定間隔で繰り返し実行する。実行中のクエリやテーブルの件数など、時間とともに変化する値を監視する場合に使う。
まずクエリを実行し、続けて\watchを入力する。
testdb=# SELECT count(*) FROM access_log;
count
-------
5
(1 row)
testdb=# \watch
Mon 27 Jul 2026 02:05:51 PM UTC (every 2s)
count
-------
5
(1 row)
Mon 27 Jul 2026 02:05:53 PM UTC (every 2s)
count
-------
6
(1 row)
実行のたびに、クエリの開始時刻と実行間隔がヘッダーとして表示される。デフォルトの実行間隔は2秒である。開始時刻の表示形式はLC_TIMEのロケール設定に従う。
\watchを入力した直後に1回実行し、そのあと指定間隔での待機に入る。
監視を終了するにはCtrl+Cを押す。
実行間隔を指定する
実行間隔を変更するにはi=(interval=)で秒数を指定する。
testdb=# SELECT count(*) FROM access_log;
testdb=# \watch i=5
秒数だけを指定する古い書式も使える。
testdb=# \watch 5
小数も指定できる。\watch 0.5は0.5秒間隔で実行する。PostgreSQL 16以降では0を指定すると間隔を空けずに連続実行する。
実行回数を指定する
c=(count=)で実行回数の上限を指定する。指定した回数を実行すると自動的に終了する。
testdb=# SELECT count(*) FROM access_log;
count
-------
5
(1 row)
testdb=# \watch i=1 c=3
Mon 27 Jul 2026 02:05:51 PM UTC (every 1s)
count
-------
5
(1 row)
Mon 27 Jul 2026 02:05:52 PM UTC (every 1s)
count
-------
5
(1 row)
Mon 27 Jul 2026 02:05:53 PM UTC (every 1s)
count
-------
5
(1 row)
testdb=#
c=3を指定したため、\watchによるクエリの実行は3回で終了する。
結果が指定行数を下回ったら監視を終了する
m=(min_rows=)で継続に必要な最小行数を指定する。クエリの結果行数が指定した値を下回ると監視を終了する。
長時間かかっているクエリを監視できる。クエリの完了と同時に監視も終了する。
testdb=# SELECT pid, now() - query_start AS duration, query
testdb-# FROM pg_stat_activity
testdb-# WHERE state = 'active' AND pid <> pg_backend_pid();
pid | duration | query
-----+-----------------+---------------------
134 | 00:00:00.042177 | SELECT pg_sleep(5);
(1 row)
testdb=# \watch i=2 m=1
Mon 27 Jul 2026 02:07:52 PM UTC (every 2s)
pid | duration | query
-----+-----------------+---------------------
134 | 00:00:02.045676 | SELECT pg_sleep(5);
(1 row)
Mon 27 Jul 2026 02:07:54 PM UTC (every 2s)
pid | duration | query
-----+-----------------+---------------------
134 | 00:00:04.045173 | SELECT pg_sleep(5);
(1 row)
Mon 27 Jul 2026 02:07:56 PM UTC (every 2s)
pid | duration | query
-----+----------+-------
(0 rows)
testdb=#
監視対象のクエリが完了して結果が0行になったため、m=1の条件を満たさなくなり監視が終了する。条件を下回った回の結果も一度表示してから終了する。
pg_stat_activityから自分自身の接続を除くためにpid <> pg_backend_pid()を指定している点に注意する。除外しないと監視用のクエリ自身が常に結果へ含まれるため、監視が終了しない。
参考: 【PostgreSQL】pg_stat_activityで実行中クエリとロック待ちを確認する
オプションが使えるバージョン
i=、c=、m=が使えるバージョンは以下のとおり。
| オプション | 意味 | 追加バージョン |
|---|---|---|
i=(interval=) | 実行間隔(秒) | PostgreSQL 16 |
c=(count=) | 実行回数の上限 | PostgreSQL 16 |
m=(min_rows=) | 継続に必要な最小行数 | PostgreSQL 17 |
利用可否はpsqlクライアントのバージョンで決まる。PostgreSQL 18のサーバーへ接続していても、psqlが15であればm=は使えない。
PostgreSQL 15以前では\watch 5のように秒数のみを指定する。名前付きの指定はエラーにならず黙って無視され、1秒間隔で実行される。
$ psql --version
psql (PostgreSQL) 15.18
testdb=# SELECT count(*) FROM access_log;
testdb=# \watch i=5
Mon 27 Jul 2026 02:23:35 PM UTC (every 1s)
i=5を指定しても1秒間隔で実行される。
デフォルトの実行間隔を変更する
PostgreSQL 18以降ではWATCH_INTERVAL変数でデフォルトの実行間隔を変更できる。
testdb=# \set WATCH_INTERVAL 1
testdb=# SELECT count(*) FROM access_log;
testdb=# \watch
Mon 27 Jul 2026 02:07:23 PM UTC (every 1s)
i=を指定しなくても1秒間隔で実行される。毎回同じ間隔を指定する手間を省ける。
~/.psqlrcに記述しておくと、psqlの起動時に常に適用される。
\set WATCH_INTERVAL 1
出力にタイトルをつける
複数のターミナルで別々のクエリを監視する場合、\pset titleで見出しを付けると区別しやすい。
testdb=# \pset title 'アクセス数'
Title is "アクセス数".
testdb=# SELECT count(*) FROM access_log;
アクセス数
count
-------
5
(1 row)
testdb=# \watch i=1
アクセス数 Mon 27 Jul 2026 02:06:09 PM UTC (every 1s)
count
-------
5
(1 row)
タイトルは各実行のヘッダー行にも表示される。
具体例: VACUUMの進捗を監視する
大きなテーブルのVACUUMは完了まで時間がかかるため、\watchとの相性がよい。
testdb=# SELECT pid, phase, heap_blks_total, heap_blks_scanned FROM pg_stat_progress_vacuum;
pid | phase | heap_blks_total | heap_blks_scanned
-----+---------------+-----------------+-------------------
206 | scanning heap | 41728 | 1096
(1 row)
testdb=# \watch i=2
Mon 27 Jul 2026 02:09:28 PM UTC (every 2s)
pid | phase | heap_blks_total | heap_blks_scanned
-----+---------------+-----------------+-------------------
206 | scanning heap | 41728 | 1096
(1 row)
Mon 27 Jul 2026 02:09:30 PM UTC (every 2s)
pid | phase | heap_blks_total | heap_blks_scanned
-----+---------------+-----------------+-------------------
206 | scanning heap | 41728 | 1843
(1 row)
heap_blks_scannedが増えていく様子を追える。m=1を組み合わせるとVACUUMの完了と同時に監視を終了できる。
参考: 【PostgreSQL】pg_stat_progress_vacuumでVACUUMの進捗を確認する
クエリがエラーになると終了する
\watchは繰り返し実行中のクエリが失敗した時点で終了する。
testdb=# SELECT count(*) FROM no_such_table;
ERROR: relation "no_such_table" does not exist
LINE 1: SELECT count(*) FROM no_such_table;
^
testdb=# \watch i=1 c=3
ERROR: relation "no_such_table" does not exist
LINE 1: SELECT count(*) FROM no_such_table;
^
testdb=#
c=3を指定しても、1回目のエラーで終了する。
更新クエリも繰り返される
\watchは直前のクエリバッファをそのまま再実行するため、SELECT以外のクエリも繰り返し実行される。
testdb=# INSERT INTO access_log (path) VALUES ('/watch-test');
INSERT 0 1
testdb=# \watch i=1 c=2
INSERT 0 1
INSERT 0 1
testdb=# SELECT count(*) FROM access_log;
count
-------
8
(1 row)
元の実行と合わせて3行が挿入される。\watchの直前に実行したクエリが参照系であるかを確認してから実行する。
シェルのwatchコマンドとの違い
シェルのwatchコマンドでも同様の監視ができる。
$ watch -n 2 psql -d testdb -c "SELECT count(*) FROM access_log;"
シェルのwatchは実行のたびにpsqlのプロセス起動とデータベースへの接続が発生する。psqlの\watchは同一セッションを使い続けるため、接続のオーバーヘッドがない。一時テーブルやPREPAREした文もそのまま使える。
一方でシェルのwatchは画面をクリアして最新の結果のみを表示する。psqlの\watchは結果を書き足していく。画面をクリアしたい場合はPSQL_WATCH_PAGER環境変数にページャーを指定する。指定できるのはUnix系のシステムのみで、psqlの出力形式を解釈できるページャーが必要である。別途インストールしたpspgであれば--streamオプションを付けて指定する。
$ PSQL_WATCH_PAGER="pspg --stream" psql -d testdb
