データ型を選ぶのは、作業用の道具を選ぶのと同じ感じ。ネジ回しで釘を打つやつはいないよね(たぶん)。データベースでも同じで、正しいデータ型を選ぶとパフォーマンスも良くなるし、メモリも節約できて、データ管理もラクになる。例えば、お金をREALで保存したら精度の問題が出るし、短い文字列にTEXTじゃなくてVARCHARを使えばメモリも節約できる。
データ型を選ぶときは、いくつかポイントを考えよう:
データの性質
そのデータがどんなカテゴリか考えよう:数字、文字列、論理値、日付、それとももっと複雑なJSON構造とか。
データ量
どれくらいのデータを保存する予定?例えば、50文字までのテキストならTEXTよりVARCHAR(50)の方がいいよ。
精度と範囲
高い精度が必要?(例えばお金の計算とか)値の範囲を制限したい?
クエリの頻度や性質
どれくらいデータにアクセスする?JSONBみたいな複雑な型は処理にリソースが多くかかるから注意。
データ型選びの例
データによってやることも違う。細かい金額が大事なときもあれば、とにかく全部入ればOKなときもある。下に、状況ごとに合ったデータ型の選び方を例でまとめたよ。
お金のデータ
お金を保存するときは、会計と同じでミスは許されない。だからNUMERIC型がベスト。これなら精度バッチリ。例えばこんなカラムのテーブルを作りたいとき:
| カラム名 | データ型 | コメント |
|---|---|---|
| id | SERIAL | 主キー |
| amount | NUMERIC(10, 2) | 10桁で小数点以下2桁 |
| currency_code | CHAR(3) | ISO通貨コード、例:"USD", "EUR" |
| transaction_date | TIMESTAMP | 取引日時、デフォルトは現在時刻 |
なんでREALじゃダメなの?浮動小数点数は精度が落ちることがあるから、お金には致命的なんだ。
文字列データ
ユーザー名や住所とか、文字列を保存するなら、できるだけ最大長を決めておこう。例えばTEXTよりVARCHAR(50)。これでエラーも減るし、メモリも最適化できる。
| カラム名 | データ型 | コメント |
|---|---|---|
| id | SERIAL | 主キー |
| username | VARCHAR(50) | ユーザーログイン、ユニークで必須 |
| VARCHAR(255) | メールアドレス | |
| bio | TEXT | 自己紹介、長文OK |
もし文字列の長さが完全に決まってる(例えば国コード2文字とか)なら、CHARを使おう:
| カラム名 | データ型 | コメント |
|---|---|---|
| code | CHAR(2) | ISO国コード(例:"US")、主キー |
| name | VARCHAR(100) | 国名、必須 |
タイムスタンプ用データ
イベントやスケジュールの時間を保存するなら、TIMESTAMPがよく使われる。日付と時間が両方入るから便利。
| カラム名 | データ型 | コメント |
|---|---|---|
| id | SERIAL | 主キー |
| event_name | VARCHAR(100) | イベント名 |
| start_time | TIMESTAMP | イベント開始時刻、必須 |
| end_time | TIMESTAMP | イベント終了時刻、必須 |
日付だけならDATE、時間だけならTIMEを使おう。
ユニークID
グローバルにユニークなIDが必要なときはUUIDを使おう。例えばトランザクションのユニークIDを作るなら:
| カラム名 | データ型 | コメント |
|---|---|---|
| request_id | UUID | リクエストのユニークID、デフォルトでgen_random_uuid()で生成 |
| endpoint | VARCHAR(255) | 呼び出し先APIエンドポイントのアドレス |
| timestamp | TIMESTAMP | リクエスト時刻、デフォルトは現在時刻 |
JSONB:複雑な構造
構造が変わるかもとか、複雑なデータ(ユーザー設定やメタデータなど)を保存したいときはJSONBが便利。
| カラム名 | データ型 | コメント |
|---|---|---|
| user_id | SERIAL | 主キー(ユーザーID) |
| preferences | JSONB | ユーザー設定(JSON形式) |
JSONBは便利だけど、挿入や更新が多いとパフォーマンスが落ちることもあるから注意。
配列
同じ種類のデータをリストで保存したいときは配列が使える。例えばタグのリスト:
| カラム名 | データ型 | コメント |
|---|---|---|
| id | SERIAL | 主キー |
| title | VARCHAR(255) | 記事タイトル |
| tags | TEXT[] | タグの配列 |
タスク別データ型まとめ
| タスクの種類 | おすすめデータ型 | 例 |
|---|---|---|
| レコードID | SERIAL, BIGSERIAL, UUID |
id SERIAL PRIMARY KEY |
| 数量・整数 | INTEGER, BIGINT |
quantity INTEGER |
| お金の計算 | NUMERIC |
price NUMERIC(10, 2) |
| 文字列の保存 | VARCHAR(n), TEXT |
username VARCHAR(50) |
| 短い固定長文字列 | CHAR(n) |
status CHAR(1) |
| 日付と時間 | DATE, TIME, TIMESTAMP |
created_at TIMESTAMP DEFAULT NOW() |
| ユニークID | UUID |
id UUID PRIMARY KEY DEFAULT gen_random_uuid() |
| 複雑な構造(JSON) | JSONB |
metadata JSONB |
| 値のリスト | ARRAY |
tags TEXT[] |
| 論理値 | BOOLEAN |
is_active BOOLEAN |
たぶんSERIAL以外はもう知ってるよね。SERIALは実はINTEGERと同じで、テーブルの行IDとして使われるんだ。
新しい行を追加すると自動で1ずつ増える。だから10行追加したら、最初の行のidは1、2行目は2、って感じ。詳しくは次のレクチャーで説明するね :)
GO TO FULL VERSION