PostgreSQLの「裏側」を覗いてみよう!システムカタログの秘密
おいっす! Postgres歴長めのエンジニアだよ。今日はね、普段みんなが当たり前のように使ってるPostgreSQLの「裏側」に隠された、ちょっと面白い仕組みについて話そうと思うんだ。
「システムカタログ」って言葉、聞いたことあるかな? もしかしたら「何それ、難しそう…」って思ったかもしれないけど、実はこれ、データベースがどうやって動いてるかを知るための「地図」みたいなものなんだ。これを理解しておくと、普段のDB操作がもっとスムーズになるし、トラブルシューティングの時にも役立つこと間違いなし!
今回は、そんなシステムカタログの中でも特に重要な「`pg_class`」「`pg_attribute`」「`pg_type`」あたりを中心に、どんな情報が詰まってて、どうやって見ればいいのか、具体的な例を交えながら解説していくよ。
システムカタログって、そもそも何?
まずは基本からね。システムカタログっていうのは、PostgreSQL自身が、データベース内のあらゆるオブジェクト(テーブル、インデックス、関数、データ型とかね)の情報を管理するために使ってる特別なテーブル群のことなんだ。
例えるなら、図書館の蔵書目録みたいなものかな。どの本がどこにあって、どんな内容で、誰が借りてるか、なんて情報が全部記録されてるでしょ? システムカタログも同じで、
- テーブルの名前は?
- そのテーブルにはどんなカラムがあるの?
- カラムのデータ型は何?
- インデックスはどんなのが張ってある?
- ビューの定義は?
…みたいな、データベースに関する「メタデータ」が全部ここに詰まってるんだ。
普段、私たちが `SELECT FROM users;` とか `CREATE TABLE products (…)` ってコマンドを打つとき、PostgreSQLの内部では、このシステムカタログを参照して、要求された操作を実行してるんだよ。すごいよね!
現場で役立つ!主要なシステムカタログを見てみよう
さて、ここからが本題。システムカタログって、実はものすごーくたくさんあるんだけど、まずは現場でよくお世話になる、代表的なものをいくつか見ていこう。
1. `pg_class`: オブジェクトの「親玉」カタログ
`pg_class` は、テーブル、インデックス、シーケンス、ビュー… といった、データベース内の「関係(リレーション)」と呼ばれるオブジェクトの情報を管理してるカタログなんだ。
- テーブル名: `pg_class`
- どんな情報がある?
- `relname`: オブジェクトの名前(テーブル名とかビュー名とか)
- `relnamespace`: オブジェクトが属するスキーマのID
- `relkind`: オブジェクトの種類(’r’ ならテーブル、’i’ ならインデックス、’v’ ならビュー…)
- `reltablespace`: オブジェクトが格納されているテーブルスペースのID
- `reltuples`: テーブルの行数の推定値
- `relpages`: テーブルが占めるページ数
実際にどんなデータが入ってるか、見てみようか。例えば、`public` スキーマにあるテーブル一覧を見たいときは、こんなクエリになるよ。
SELECT
c.relname AS table_name,
n.nspname AS schema_name,
CASE c.relkind
WHEN ‘r’ THEN ‘TABLE’
WHEN ‘v’ THEN ‘VIEW’
WHEN ‘i’ THEN ‘INDEX’
WHEN ‘s’ THEN ‘SEQUENCE’
WHEN ‘m’ THEN ‘MATERIALIZED VIEW’
ELSE c.relkind::text
END AS object_type
FROM
pg_class c
JOIN
pg_namespace n ON c.relnamespace = n.oid
WHERE
n.nspname = ‘public’ — publicスキーマに限定
AND c.relkind IN (‘r’, ‘v’, ‘m’) — TABLE, VIEW, MATERIALIZED VIEW に限定
ORDER BY
c.relname;
このクエリを実行すると、`public` スキーマにあるテーブルやビューの名前、種類が表示されるはずだよ。`pg_namespace` と `JOIN` してるのは、`pg_class` だけだとスキーマ名が直接分からないからなんだ。`relkind` の `CASE` 文で、`relkind` のコードを分かりやすい名前に変換してるのもポイントね。
2. `pg_attribute`: カラムの「詳細情報」カタログ
テーブルの構造を知りたい、ってときにお世話になるのが `pg_attribute` だ。これは、テーブルのカラム(属性)に関する情報を保持してるんだ。
- テーブル名: `pg_attribute`
- どんな情報がある?
- `attrelid`: カラムが所属するテーブルの `pg_class` の `oid`
- `attname`: カラムの名前
- `atttypid`: カラムのデータ型を表す `pg_type` の `oid`
- `attnum`: カラムの番号(1から始まる)
- `attnotnull`: NOT NULL 制約があるか(boolean)
- `atthasdef`: デフォルト値があるか(boolean)
- `attacl`: アクセス権限
`pg_attribute` を使うときは、必ず `pg_class` と `JOIN` して、どのテーブルのカラムなのかを特定する必要があるんだ。例えば、`users` テーブルのカラム情報を見るなら、こんな感じ。
SELECT
a.attname AS column_name,
pg_catalog.format_type(a.atttypid, a.atttypmod) AS data_type,
CASE
WHEN a.attnotnull THEN ‘NOT NULL’
ELSE ‘NULLABLE’
END AS nullability,
CASE
WHEN a.atthasdef THEN ‘HAS DEFAULT’
ELSE ‘NO DEFAULT’
END AS default_status
FROM
pg_attribute a
JOIN
pg_class c ON a.attrelid = c.oid
WHERE
c.relname = ‘users’ — 対象のテーブル名
AND a.attnum > 0 — システムカラムを除外
AND NOT a.attisdropped — 削除されたカラムを除外
ORDER BY
a.attnum;
このクエリで、`users` テーブルのカラム名、データ型、NULL許容か、デフォルト値があるか、といった情報が取れるはずだよ。`pg_catalog.format_type` っていう関数を使ってるのがミソ。これで `atttypid` だけじゃなくて、ちゃんと型名(`varchar(255)` とか)まで表示してくれるんだ。便利でしょ?
3. `pg_type`: データ型の「名簿」カタログ
カラムのデータ型が知りたいとき、`pg_attribute` の `atttypid` だけでは、それが何型なのか直接分かりにくいことがある。そこで登場するのが `pg_type` だ。これは、PostgreSQLが持ってる全てのデータ型に関する情報を管理してるカタログだよ。
- テーブル名: `pg_type`
- どんな情報がある?
- `typname`: データ型の名前(`int4`, `varchar`, `timestamp` など)
- `typnamespace`: データ型が属するスキーマのID
- `typtype`: データ型の種類(’b’ なら基本型、’c’ なら複合型、’d’ ならドメイン…)
- `typcategory`: データ型のカテゴリ(数値、文字、日付/時刻など)
さっきの `pg_attribute` の例で `pg_catalog.format_type` を使ったけど、もし `atttypid` しかなくて、それを `pg_type` で調べたいときは、こんな感じになる。
SELECT
t.typname AS type_name,
t.typtype AS type_kind,
n.nspname AS schema_name
FROM
pg_type t
JOIN
pg_namespace n ON t.typnamespace = n.oid
WHERE
t.oid = (SELECT atttypid FROM pg_attribute WHERE attrelid = ‘users’::regclass AND attname = ‘email’); — usersテーブルのemailカラムのatttypidを取得して検索
ちょっと複雑に見えるかもしれないけど、`users` テーブルの `email` カラムの `atttypid` を取得して、それを `pg_type` で検索してるんだ。`’users’::regclass` って書くと、テーブル名を `pg_class` の `oid` に自動で変換してくれるから便利だよ。
システムカタログを「読む」ときの注意点
ここまで、システムカタログのいくつかを見てきたけど、これらを直接クエリで参照する際に、いくつか覚えておいてほしいことがあるんだ。
- PostgreSQLのバージョンアップで構造が変わる可能性: システムカタログはPostgreSQLの内部実装に関わる部分だから、メジャーバージョンアップなどで構造が変わったり、新しいカラムが追加されたりすることがある。なので、常に最新のPostgreSQLドキュメントを参照するのが鉄則だよ。
- 直接 `UPDATE` や `DELETE` はしない!: システムカタログはDBの「心臓部」みたいなもの。ここに直接 `UPDATE` や `DELETE` を実行すると、データベースが壊れる原因になりかねない。参照(SELECT)だけにするのが絶対ルールだよ。
- `pg_catalog` スキーマ: システムカタログは、デフォルトで `pg_catalog` というスキーマに属してる。だから、クエリでスキーマ名を指定しない場合でも、PostgreSQLは自動的に `pg_catalog` を探してくれる(though `search_path` の設定にもよるけどね)。でも、明示的に `pg_catalog.pg_class` のように指定した方が、より確実ではあるよ。
- `oid` で繋がってる: システムカタログ同士は、`oid` (Object Identifier) という一意なIDで繋がってる場合が多い。これを理解して `JOIN` していくのが、システムカタログを使いこなすコツなんだ。
なぜ、システムカタログを知っておくと良いのか?
「そこまでしなくても、標準的なSQLで十分じゃない?」って思うかもしれない。確かに、日常的なDB操作なら、それで困ることは少ないだろう。でも、システムカタログを知っておくと、こんなメリットがあるんだ。
- DBの内部構造の理解が深まる: 普段使ってるコマンドが、裏側でどう動いてるのかが見えるようになる。これは、DBのパフォーマンスチューニングや、設計を考える上で非常に重要。
- 標準機能ではできない情報の取得: 例えば、テーブルの行数やディスク使用量、インデックスのキー情報などを、より詳細に、あるいは別の角度から取得したい場合、システムカタログを直接調べるのが一番早いことが多い。
- トラブルシューティングの強力な武器に: 「あれ?なんでこのテーブル、遅いんだろう?」とか、「このインデックス、本当に使われてる?」みたいな疑問が出てきたときに、システムカタログを調べることで、原因究明の手がかりが得られることがある。
- DB管理ツールの裏側を知る: pgAdminとか、DBeaverみたいなGUIツールも、内部ではシステムカタログを叩いて情報を表示してるんだ。それを知ってると、ツールの挙動を理解する助けになるし、もっと賢くツールを使えるようになる。
まとめ
今日は、PostgreSQLのシステムカタログ、特に `pg_class`, `pg_attribute`, `pg_type` について、その概念と具体的な使い方を解説したよ。
最初はちょっと戸惑うかもしれないけど、これらのカタログを「データベースの地図」として捉えて、色々と `SELECT` してみてほしい。きっと、PostgreSQLの世界がもっと面白く見えるようになるはずだから!
もし「こんな情報が欲しいんだけど、どのカタログを見ればいいの?」とか、「このクエリ、もっと効率良くならない?」なんて疑問があったら、いつでも聞いてね。現場で培った知恵を、惜しみなく伝授するよ!
じゃあ、またね!
コメント