【テクニカル・上級編】 基本データ型 – PostgreSQL

データ型を制する者はPostgreSQLを制す:最適化の深淵へようこそ

PostgreSQLを触り始めて数年、あるいは数十年。私たちは日々、SQLのクエリを書き、インデックスを貼り、パフォーマンスのチューニングに頭を悩ませています。しかし、ふと立ち止まって考えてみてください。「なぜこのデータ型を選んだのか?」を即座に、技術的根拠を持って説明できるでしょうか。

データ型は単なる「データの入れ物」ではありません。それはストレージの物理配置、CPUの演算効率、そしてプランナの判断基準を左右する「基盤」です。今日は、教科書的な説明はすっ飛ばして、PostgreSQLの内部アーキテクチャに深く切り込んだ話をしましょう。

—

1. 数値型:`integer`の静かなる支配と`numeric`の代償

`integer`(4バイト)は、現代のハードウェアにおいて最も効率的な型の一つです。アライメントの観点からも非常に扱いやすく、基本的にはこれを使うべきです。

一方で、金銭計算などで安易に`numeric`を選んでいないでしょうか? `numeric`は可変長型であり、内部的には複雑な構造を持っています。精度を保証するためのオーバーヘッドは無視できず、大量の演算が絡む集計処理では、`integer`(例えば「円」ではなく「銭」単位で管理する)や`bigint`での代替が、桁違いのパフォーマンス向上をもたらすことが多々あります。

  • 教訓: `numeric`は必要なときだけ使う。物理的なメモリ消費とCPUサイクルを意識せよ。

2. 文字列型:`text` vs `varchar(n)` の終わらない議論

PostgreSQLのソースコードを覗いたことがある方ならご存知でしょうが、実は`text`と`varchar`は内部的には全く同じ構造(`varlena`型)です。

「じゃあ`varchar(n)`に意味はないのか?」というと、そうではありません。`varchar(n)`は、アプリケーション層でのバリデーションをデータベース側に押し付ける「制約」として機能します。しかし、パフォーマンス面で言えば、`text`型を使っておき、アプリケーション側で制御する方が、スキーマ変更の柔軟性(`ALTER TABLE`のコストなど)を考えると賢明な場合が多いです。

また、`text`や`varchar`は「TOAST(The Oversized-Attribute Storage Technique)」の対象になります。カラムが長くなると外部ストレージに追い出されるこの仕組みを理解していないと、行内のデータアクセスだと思っていた処理が、実はディスクI/Oを激しく叩く「TOASTテーブルへのランダムアクセス」を引き起こし、クエリを低速化させる主犯になります。

3. 真偽値型:`boolean`という名の1バイト

PostgreSQLの`boolean`は、文字通り1バイトを消費します。以前、`char(1)`でフラグを管理しているレガシーDBのマイグレーションをした際、`boolean`に書き換えるだけでストレージ効率が劇的に改善し、インデックスサイズが縮小した経験があります。

また、PostgreSQLの`boolean`は`IS TRUE` / `IS FALSE`といったSQL標準の構文と非常に相性が良く、クエリの可読性を高めるだけでなく、プランナが統計情報から「このカラムの分布」をより正確に予測できるという副次的なメリットもあります。

4. 日付・時刻型:タイムゾーンの罠

`timestamp with time zone` (timestamptz) は、名前に反してタイムゾーンを「保存」するわけではありません。内部的にはUTCに変換された整数(8バイト)として保持されます。

ここでのトラブルの典型は、アプリケーション層でタイムゾーンを変換し、DB側で再度変換するという二重の手間や、クエリの`WHERE`句で計算式(`date(created_at) = …`)を使ってしまい、インデックスが一切効かなくなる「インデックス殺し」の罠です。日付型は、常に「そのまま比較できる状態」でインデックスを貼る。これが鉄則です。

—

最後に:パフォーマンスを語る前に型を見よ

私がパフォーマンスチューニングの現場で最初に確認するのは、クエリのプランナではありません。「どんな型が使われているか」というテーブル定義です。

不適切な型選択は、以下のような負の連鎖を引き起こします。
1. メモリ効率の低下: キャッシュに乗るデータ量が減り、物理I/Oが増える。
2. アライメントの悪化: タプルのサイズが大きくなり、ページあたりの格納効率が下がる。
3. 演算のオーバーヘッド: 型変換(Cast)が暗黙的に発生し、インデックススキャンが拒否される。

データ型を理解することは、PostgreSQLというエンジンの仕組みを理解することと同義です。皆さんも、次に`CREATE TABLE`を書くとき、あるいは`ALTER`を叩くとき、その型が物理メモリの上でどう振る舞うのか、一度立ち止まって想像してみてください。

PostgreSQLは、その問いかけに対して、必ず高速なレスポンスという形で応えてくれるはずです。それでは、良きデータベースライフを!

コメント

タイトルとURLをコピーしました