0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PostgreSQL 18がやってくる(4) psqlの改善

Last updated at Posted at 2025-04-06

はじめに

にゃーん。
今回はPostgreSQLの対話的ターミナルpsqlのPostgreSQL 18での改善項目について調べてみた。

調査方法

  • 調査対象の改善項目は2025-04-5時点のCommitfest 2025-03に上がっている項目でStatus=Commitedかつ、Text=psqlタのものとした(4項目)。
    • この探し方だと、psqlという文言は含まないけど、実はpsqlの改善だったという項目が漏れてしまう・・・やっぱりClientsカテゴリの項目は一通りチェックしないとダメっぽい。
  • 本記事ではCommitログのみで挙がっている改善項目は対象外(サボった)。
    • pgsql-commiterのMLからpsqlで引っ掛けるとCommitfest以外の項目(マテビューのTAB補完とか)等々もいくつか引っかかるが今回は割愛。
  • 実機検証はCommit 683df3f(2024-04-06)のmasterブランチのコードをビルドした版を使った。

改善項目概要

Commitfestに挙がっていたpsqlに関する改善項目を列挙する。

  • psql meta-command conninfo+
    conninfoメタコマンドの改善
  • Allow default \watch interval in psql to be configured
    \watch メタコマンドのデフォルト間隔値の設定
  • Add Pipelining support to psql
    パイプラインモードのサポート
  • Better title output for psql \dt \di \dv \dm \ds \dE
    カタログ表示系メタコマンドのタイトル表示改善

改善項目詳細

Commitfestで挙がっていた項目の内容をもう少し詳しく調べてみた。

conninfoメタコマンドの改善

これは\conninfoに詳細表示オプション\conninfo+を追加した、という改善のようだ。

conninfoはPostgreSQL 16からpsqlで使用可能なメタコマンド。
現在のデータベース接続に関する情報を出力する。
PostgreSQL 17までは以下のような1行の文字列として情報を出力していた。

$ ~/pgsql/pgsql-17/bin/psql -p 17001 -U testuser testdb
psql (17.0)
Type "help" for help.

testdb=> \conninfo
You are connected to database "testdb" as user "testuser" via socket in "/tmp" at port "17001".
testdb=>

PostgreSQL 18からは接続に関する情報をParameter,Valueの列として、各情報を別レコードの形式で出力するように改善された。

$ psql -p 18001 testdb -U testuser
psql (18devel)
Type "help" for help.

testdb=> \conninfo
     Connection Information
      Parameter       |  Value
----------------------+----------
 Database             | testdb
 Client User          | testuser
 Socket Directory     | /tmp
 Server Port          | 18001
 Options              |
 Protocol Version     | 3
 Password Used        | false
 GSSAPI Authenticated | false
 Backend PID          | 28426
 TLS Connection       | false
 Superuser            | off
 Hot Standby          | off
(12 rows)

\conninfoで出力されるParameterの種類は接続方法によって異なる。
例えば上記の例はUnixドメインソケットによる接続(-h hostnameを付けない接続)の例だが、-h hostnameを付与した接続の場合は、以下のようにParameterの内容も異なる(Socket Directory行がなくなり、代わりにHost行とHost Address行が追加されている)。

$ psql -p 18001 -h localhost testdb -U testuser
psql (18devel)
Type "help" for help.

testdb=> \conninfo
      Connection Information
      Parameter       |   Value
----------------------+-----------
 Database             | testdb
 Client User          | testuser
 Host                 | localhost
 Host Address         | 127.0.0.1
 Server Port          | 18001
 Options              |
 Protocol Version     | 3
 Password Used        | false
 GSSAPI Authenticated | false
 Backend PID          | 29418
 TLS Connection       | false
 Superuser            | off
 Hot Standby          | off
(13 rows)

Parameterの出力順序はアルファベット順ではなく、\conninfo機能(exec_command_conninfo()関数の実装)で固定となっている。

もともと、この機能が提案されたときには、\conninfoは従来のようにテキスト1行で出力、\conninfo+を指定したときに、Parameterごとに別の行で出力するという提案だったようだが、MLでの議論の結果、\conninfoで別の行に出力するようになったらしい(つまりPostgreSQL 17までの出力形式とは非互換)。
またconninfo+自体は現時点では実装されていない。

testdb=> \conninfo+
invalid command \conninfo+
Try \? for help.

\watch メタコマンドのデフォルト間隔値の設定

psqlには特別に定義された「変数」がある。(Variables参照)
PostgreSQL 18では、この変数としてWATCH_INTERVALが追加された。
このWATCH_INTERVALはデフォルトでは2が設定されている。

postgres@postgres=# \echo :WATCH_INTERVAL
2
postgres@postgres=#

このため\watchメタコマンドを引数なしで実行すると2秒間隔で直前のSQLコマンドを実行する。
以下にデフォルト状態でのwatchメタコマンドの実行例を示す。デフォルトだと(約)2秒間隔で、SELECT now()が実行されているのがわかる。

postgres@postgres=# \t
Tuples only is on.
postgres@postgres=# SELECT now();
 2025-04-06 09:48:06.070375+09

postgres@postgres=# \watch
 2025-04-06 09:48:11.181377+09

 2025-04-06 09:48:13.181536+09

 2025-04-06 09:48:15.181516+09

WATCH_INTERVAL変数の値を変更する場合は、psqlの\setコマンドを使う。
\setコマンドでWATCH_INTERVALの値を0.5(秒)に設定し、SQLコマンド実行後にwatchメタコマンドを実行した例を以下に示す。

postgres@postgres=# \t
Tuples only is on.
postgres@postgres=# \echo :WATCH_INTERVAL
2
postgres@postgres=# \set WATCH_INTERVAL 0.5
postgres@postgres=# SELECT now();
 2025-04-06 09:57:11.355264+09

postgres@postgres=# \watch
 2025-04-06 09:57:18.007455+09

 2025-04-06 09:57:18.507585+09

 2025-04-06 09:57:19.00757+09

 2025-04-06 09:57:19.507603+09

 2025-04-06 09:57:20.007538+09

\watchメタコマンドによって約0.5秒間隔でSELECT now()が実行されている。

\set wまで入力した状態で、TABキーを押すと、\set WATCH_INTERVAL と補完してくれるので、あとは間隔の数値を入力するだけでOK。
(これに頼りすぎると変数名を覚えなくなるという諸刃の剣ではあるが)

PsotgreSQL 17以前の版では\echo :WATCH_INTERVALを実行してもエラーにはならず、:WATCH_INTERVALと出力されます。

postgres@postgres=# \echo :WATCH_INTERVAL
:WATCH_INTERVAL
postgres@postgres=#

パイプラインモードのサポート

パイプラインモードのサポートというのは、PostgreSQL 14から利用可能になった、libpq拡張プロトコルを使った実行モードの一つ。このモードは

  • 以前に送信された問い合わせの結果を読み込まなくても問い合わせを送信できる。
  • パイプラインモードを利用すると、1つのネットワークトランザクションで複数の問い合わせ/結果を送受信できる。
  • クライアントはサーバを待つ時間が少なくなる。

というもの。
このパイプラインモードは別のクライアントツールpgbench(PostgreSQLに対してベンチマーク試験を行う)では、PostgreSQL 14から使用可能だった(自分も以前調査したことがある。ぜんぜんわからない。俺たちは雰囲気でpgbenchを使っていた。参照)

PostgreSQL 18では、pgbenchと同様のメタコマンドをpsqlでも使用可能になった。
PostgreSQL 18のpsqlでは以下のパイプラインに関するメタコマンドを提供している。

メタコマンド名 パラメータ 機能
\startpipeline (なし) パイプラインを開始する。
\sendpipeline (なし) 現在のクエリバッファをパイプラインに追加する。
\syncpipeline (なし) 送信バッファをフラッシュすることなく同期メッセージを送信する。
\endpipeline (なし) パイプラインを終了する。
\flushrequest (なし) パイプラインに\flushコマンドを追加し、同期を発行したりパイプラインを終了したりせずに、\getresultsで結果を読み取り可能にする。
\flush (なし) 未送信のデータを手動でプッシュするために使用する。
\getresults [ number_results ] # \getresultsはオプションのnumber_resultsパラメータ(#)を受け付ける。指定された場合、最初の number_results 個の保留中の結果のみが読み取られる。指定がない場合、または 0 の場合は、保留中のすべての結果が読み取られる。

たとえば、以下の3つのSELECT文

SELECT 1, now();
SELECT pg_sleep(3);
SELECT 2, now();

をパイプラインなし実行した場合は、以下のようになる。

$ psql -a -p 18001 testdb -U testuser -f no-pipeline-0.sql
\timing
Timing is on.
SELECT 1, clock_timestamp();
 ?column? |        clock_timestamp
----------+-------------------------------
        1 | 2025-04-06 15:48:08.098753+09
(1 row)

Time: 0.503 ms
SELECT 2,pg_sleep(3);
 ?column? | pg_sleep
----------+----------
        2 |
(1 row)

Time: 3003.577 ms (00:03.004)
SELECT 3, clock_timestamp();
 ?column? |        clock_timestamp
----------+-------------------------------
        3 | 2025-04-06 15:48:11.102694+09
(1 row)

3つ目のSELECT文は2つ目のSELECT pg_sleep(3)が実行される3秒後に実行される。

同じ3つのSELECT分をパイプラインモードで実行した場合には以下のようになる。

$ psql -a -p 18001 testdb -U testuser -f pipeline-0.sql
\timing
Timing is on.
\startpipeline
Time: 0.000 ms
SELECT 1, clock_timestamp();
Time: 0.000 ms
SELECT 2,pg_sleep(3);
Time: 0.000 ms
SELECT 3, clock_timestamp();
Time: 0.000 ms
\endpipeline
 ?column? |        clock_timestamp
----------+-------------------------------
        1 | 2025-04-06 15:48:42.308991+09
(1 row)

 ?column? | pg_sleep
----------+----------
        2 |
(1 row)

 ?column? |        clock_timestamp
----------+-------------------------------
        3 | 2025-04-06 15:48:45.312447+09
(1 row)

Time: 3004.142 ms (00:03.004)

3つのSELECT文は(見た目上は)待ち時間なくすぐにプロンプトを返却する。
そして、\endpipelineメタコマンドのあとで、パイプライン全体のSELECT文を実行する。
そのあと、各SELECT文の結果が順次出力される。
\timingメタコマンドで返却される時間はパイプライン全体の時間となる。

動作方法はわかったのだが。実運用でこの機能を使うケースが実はあんまり想定できていない・・・。

この機能の提案メールを読んだ感じでは、パイプラインモードの試験のときに、ppgbenchを使ったTAPテストしかできなかったので、psqlを使って簡単にテストできるようにするのが目的のようにも読める・・・。

カタログ表示系メタコマンドのタイトル表示改善

psqlにはテーブルの一覧や、テーブル内の列一覧を表示する等のカタログ表示系メタコマンドが多数用意されている。
PostgreSQL 17まではどのオブジェクト種別であってもタイトル行はList of relationsを表示していた。(以下はテーブルの例)

\dt test_t
         List of relations
 Schema |  Name  | Type  |  Owner
--------+--------+-------+----------
 public | test_t | table | postgre
(1 row)

PostgreSQL 18ではオブジェクト種別に応じて適切なタイトル行に修正された。

メタコマンド 表示対象のオブジェクト種別 修正後のタイトル文字列
\dt テーブル List of tables
\di インデックス List of indexes
\dv ビュー List of views
\dm マテリアライズド・ビュー List of materialized views
\ds シーケンス List of sequences
\dE 外部テーブル List of foreign tables

PostgreSQL 18での\dt,\di,\ds,\dv,\dmの実行例を以下に示す。
(外部テーブル(\dE)は作るのが少し面倒なので今回は割愛)

$ psql -p 18001 -U postgres testdb -a -f d_metacommand.sql
\dt test_t
           List of tables
 Schema |  Name  | Type  |  Owner
--------+--------+-------+----------
 public | test_t | table | postgres
(1 row)

\di test_t_id_idx
                  List of indexes
 Schema |     Name      | Type  |  Owner   | Table
--------+---------------+-------+----------+--------
 public | test_t_id_idx | index | postgres | test_t
(1 row)

\ds test_t_seq_num_seq
                 List of sequences
 Schema |        Name        |   Type   |  Owner
--------+--------------------+----------+----------
 public | test_t_seq_num_seq | sequence | postgres
(1 row)

\dv test_v
           List of views
 Schema |  Name  | Type |  Owner
--------+--------+------+----------
 public | test_v | view | postgres
(1 row)

\dm test_mv
           List of materialized views
 Schema |  Name   |       Type        |  Owner
--------+---------+-------------------+----------
 public | test_mv | materialized view | postgres
(1 row)

おわりに

今回はCommitfestに挙がっていた4つのpsqlの改善項目を調べてみた。
Commitfestに挙がっていないpsqlの改善項目(バグFix等含む)は、別途余力があったら調べてみる。

追記

Noriyoshi Shinodaさんからのコメント。
psqlキーワードだけでCommitfestを探すと結構漏らしてしまうな・・・。
暇をみて、それぞれの項目を確認しよう。

パイプラインモードでは以下の変数が使えます。
PIPELINE_SYNC_COUNT
PIPELINE_COMMAND_COUNT
PIPELINE_RESULT_COUNT
プリペア文の定義を操作する以下のメタコマンドが追加されました。
\parse
\bind_named
\close
https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=d55322b0da60a8798ffdb8b78ef90db0fb5be18e
\dfx とか \lx とか拡張モードの出力を強制する機能
https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=978f38c771fb3a19fdd5cb73cb662441eb9e551c
変数SERVICE
https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=477728b5d6fa16461b81cd22b0568fec1eab97ac
パーティション・テーブルのアクセスメソッドを表示する \dP+
https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=978f38c771fb3a19fdd5cb73cb662441eb9e551c

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?