PostgreSQL でページの中身を視覚的に表示してみる

この記事は [PostgreSQL Advent Calendar 2022](https://qiita.com/advent-calendar/2022/postgresql) の 20 日目です。昨日は @U_ikki さんの [MERGE の挿入/更新性能の比較結果](https://qiita.com/U_ikki/items/8a2fa56120e8b07f7c97) でした。この記事ではページの中身を視覚的に表示する拡張 pagevis を紹介します。

PostgreSQL ではテーブルやインデックスのデータはページ単位でファイルに格納されますが、そのページの中身を視覚的に表示してくれる拡張が pagevis です。

https://github.com/hollobon/pagevis

pagevis をインストールすると、`show_page` 関数が使えるようになります。インストール手順はあとで紹介します。

```
show_page(
  table_name text,
  page integer,
  width integer DEFAULT 128,
  skip_hole boolean DEFAULT true
) RETURNS SETOF text
```

引数は `table_name` がテーブル名、`page` が 0 から始まるページ番号、`width` が表示幅の文字数でデフォルトは `128`、`skip_hole` が空き領域の表示を省略するかでデフォルトは `true` です。戻り値はページの中身を表す文字列の集合です。

試しにテーブルにデータを登録し、`show_page` 関数でページの中身を表示してみます。

```
=# CREATE TABLE t1 (c1 int, c2 text);
CREATE TABLE
=# INSERT INTO t1 SELECT n, md5(n::text) FROM generate_series(1, 10) AS n;
INSERT 0 10
=# SELECT * FROM t1;
 c1 |                c2
----+----------------------------------
  1 | c4ca4238a0b923820dcc509a6f75849b
  2 | c81e728d9d4c2f636f067f89cc14862c
  3 | eccbc87e4b5ce2fe28308fd9f2a7baf3
  4 | a87ff679a2f3e71d9181a67b7542122c
  5 | e4da3b7fbbce2345d7772b0674a318d5
  6 | 1679091c5a880faf6fb5e6087eb1b2dc
  7 | 8f14e45fceea167a5a36dedd4bea2543
  8 | c9f0f895fb98ab9159f51fd0297e236d
  9 | 45c48cce2e2d7fbdea1afc51c7c6ad26
 10 | d3d9446802a44259755d38e6d163e820
(10 行)

=# SELECT show_page('t1', 0, 64);
                            show_page
------------------------------------------------------------------
 PPPPPPPPPPPPPPPPPPPPPPPP001N002N003N004N005N006N007N008N009N010N
   << Hole - 117 rows skipped >>
 [10]HHHHHHHHHHHHHHHHHHHH#####################################...
 [9]HHHHHHHHHHHHHHHHHHHHH#####################################...
 [8]HHHHHHHHHHHHHHHHHHHHH#####################################...
 [7]HHHHHHHHHHHHHHHHHHHHH#####################################...
 [6]HHHHHHHHHHHHHHHHHHHHH#####################################...
 [5]HHHHHHHHHHHHHHHHHHHHH#####################################...
 [4]HHHHHHHHHHHHHHHHHHHHH#####################################...
 [3]HHHHHHHHHHHHHHHHHHHHH#####################################...
 [2]HHHHHHHHHHHHHHHHHHHHH#####################################...
 [1]HHHHHHHHHHHHHHHHHHHHH#####################################...

(13 行)
```

ページ内の文字は基本的に 1 つ 1 バイトを表し、ページの最初の `P` はページヘッダ、その後の `001N`、`002N`、`003N`、... はラインポインタを表します。ラインポインタは `[1]`、`[2]`、`[3]`、... で始まるタプルを指し示します。タプルの最初の `H` はタプルヘッダ、その後の `#` はタプルデータ、さらにその後の `.`  はパディングを表します。ラインポインタとタプルの間には空き領域があり、`<< Hole - 117 rows skipped >>` は空き領域の表示が 117 行分省略されたことを表します。ページ内の文字はほかにもあり、意味は以下のとおりです。

| 文字       | 意味                                                |
|------------|-----------------------------------------------------|
| `P`        | ページヘッダ                                        |
| `U`        | 未使用のラインポインタ                              |
| `N`        | 通常のラインポインタ                                |
| `R`        | リダイレクトのラインポインタ                        |
| `D`        | 削除済みのラインポインタ                            |
| ` ` (空白) | 空き領域 (pagevis では hole と呼ぶ)                 |
| `[n]`      | タプル番号 (タプルヘッダと重ねて表示)               |
| `H`        | タプルヘッダ                                        |
| `#`        | タプルデータ                                        |
| `-`        | 現在のトランザクションから不可視のタプル (削除済み) |
| `.`        | タプル内のパディング                                |

続いて、pagevis のインストール手順を紹介します。

PostgreSQL は [こちら](https://www.postgresql.org/download/linux/redhat/) に従ってバージョン 15 が Rocky Linux 8 にセットアップ済みであるものとします。

1. pagevis のインストール、動作に必要なパッケージをインストールします。

   ```shell-session
   $ dnf -y install make postgresql15-devel postgresql15-contrib
   (省略)
   Complete!
   ```

   pagevis は SQL スクリプトのみで構成されるので、手動でファイルをコピーすれば、`make`、`postgresql15-devel` パッケージは不要です。pagevis の動作には `postgresql15-contib` パッケージに含まれる pageinspect が必要です。

1. pagevis のソースコードをダウンロードします。

   ```shell-session
   $ curl -LO https://github.com/hollobon/pagevis/archive/refs/heads/master.tar.gz
     % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                    Dload  Upload   Total   Spent    Left  Speed
     0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
   100  4880    0  4880    0     0   6032      0 --:--:-- --:--:-- --:--:-- 12978
   ```

1. pagevis のソースコードを展開します。

   ```shell-session
   $ tar -xzf master.tar.gz
   ```

1. pagevis をインストールします。

   ```shell-session
   $ sudo make -C pagevis-master install PG_CONFIG=/usr/pgsql-15/bin/pg_config
   make: ディレクトリ '/home/vagrant/pagevis-master'　に入ります
   /usr/bin/mkdir -p '/usr/pgsql-15/share/extension'
   /usr/bin/mkdir -p '/usr/pgsql-15/share/extension'
   /usr/bin/install -c -m 644 .//pagevis.control '/usr/pgsql-15/share/extension/'
   /usr/bin/install -c -m 644 .//pagevis--0.1.sql  '/usr/pgsql-15/share/extension/'
   make: ディレクトリ '/home/vagrant/pagevis-master' から出ます
   ```

1. PostgreSQL のスーパーユーザ `postgres` に切り替わります。

   ```shell-session
   $ sudo su - postgres
   ```

1. pagevis インストール先のデータベースに接続します。

   ```shell-session
   $ psql データベース名
   ```

1. pagevis の動作に必要な pageinspect をインストールします。

   ```shell-session
   =# CREATE EXTENSION pageinspect;
   CREATE EXTENSION
   ```

1. pagevis を拡張としてインストールします。

   ```shell-session
   =# CREATE EXTENSION pagevis;
   CREATE EXTENSION
   ```

   これで pagevis のインストールは完了です。

pagevis は内部的に pageinspect を使ってページ情報を整形し、視覚的に表示するシンプルな拡張ですが、そうすることでページの中身が直感的に分かりやすくなったと思います。この記事が PostgreSQL の理解を深める手助けになればうれしいです。