🔢 STEP 4: データ型の選び方
適切なデータ型を選んで、効率的なデータベースを設計しよう
- 数値型(INT、BIGINT、DECIMAL)の使い分け
- 文字列型(VARCHAR、TEXT、CHAR)の選択基準
- 日付時刻型(DATE、DATETIME、TIMESTAMP)の違い
- データ型選択の判断基準
- 実践:適切なデータ型の選定演習
学習時間の目安: 3時間 | 前提知識: STEP 1-3修了
🎯 1. データ型とは?
STEP 3で学んだER図の次のステップ
STEP 3では、ER図を使ってエンティティと属性を視覚化する方法を学びました。例えば、以下のようなエンティティを書きました。
しかし、これだけでは実際のテーブルは作れません。なぜなら、各属性に「どんな種類のデータを入れるか」が決まっていないからです。
- 文字? → 文字列型を使う
- 何文字まで? → VARCHAR(100)?VARCHAR(255)?
- 数字? → 整数型を使う
- 0〜150くらい? → TINYINTで十分?INTが必要?
このように、各属性に適切な「箱の種類」を決めるのが、このSTEP 4の目的です。
データ型の定義
データ型(Data Type)=カラムに格納できるデータの種類とサイズを定義するもの
データ型は「箱の種類」だと考えるとわかりやすいです。
・数字を入れる箱(INT、DECIMAL など)
・文字を入れる箱(VARCHAR、TEXT など)
・日付を入れる箱(DATE、DATETIME など)
なぜデータ型の選択が重要なのか?
適切なデータ型を選ぶことで、以下のメリットがあります。
必要最小限のサイズを選ぶことで、無駄なスペースを使わない。
適切な型は検索や計算が高速。文字列型で数値を扱うと遅くなる。
型が決まっていれば、不正なデータが入らない。
型を見れば、どんなデータか一目でわかる。
- ❌ 無駄なストレージを消費する(VARCHAR(1000) で名前を格納など)
- ❌ パフォーマンス低下(不適切な型で検索が遅くなる)
- ❌ データの不整合(文字列型に数値を入れて計算ミス)
- ❌ 後からの変更が困難(既存データの移行が大変)
データ型の3大カテゴリ
1. 数値型
整数、小数点を含む数値(INT、BIGINT、DECIMAL など)
2. 文字列型
テキストデータ(VARCHAR、CHAR、TEXT など)
3. 日付時刻型
日付、時刻、タイムスタンプ(DATE、DATETIME、TIMESTAMP など)
他にも、バイナリ型(画像、ファイル)、JSON型、ENUM型などがありますが、この3つが最も基本です。それぞれ詳しく見ていきましょう。
🔢 2. 数値型の使い分け
整数型(INT系)
整数を格納するための型です。サイズによっていくつか種類があります。
| 型 | バイト数 | 範囲(符号付き) | 範囲(符号なし) |
|---|---|---|---|
| TINYINT | 1 | -128 〜 127 | 0 〜 255 |
| SMALLINT | 2 | -32,768 〜 32,767 | 0 〜 65,535 |
| MEDIUMINT | 3 | -8,388,608 〜 8,388,607 | 0 〜 16,777,215 |
| INT | 4 | 約-21億 〜 約21億 | 0 〜 約42億 |
| BIGINT | 8 | 約-922京 〜 約922京 | 0 〜 約1844京 |
整数型の選び方
「どの整数型を選べばいいの?」という疑問に答えるため、用途別に整理しました。
用途:非常に小さな範囲の整数
例:年齢(0〜150)、月(1〜12)、ステータス(0〜9)、フラグ(0 or 1)
用途:小さな範囲の整数
例:在庫数(数千個まで)、ページ番号、カウンター
用途:一般的な整数(迷ったらINT)
例:ID(主キー)、金額(円単位)、カウント数、年(西暦)
用途:非常に大きな整数
例:大量データの ID、タイムスタンプ(ミリ秒単位)、SNSのいいね数
実数型(小数点を含む数値)
小数点を含む数値には、DECIMAL、FLOAT、DOUBLEがあります。
| 型 | 特徴 | 用途 |
|---|---|---|
| DECIMAL | 固定小数点数、正確な値を保持 | 金額、会計データ |
| FLOAT | 浮動小数点数(単精度)、近似値、4バイト | 科学計算(多少の誤差OK) |
| DOUBLE | 浮動小数点数(倍精度)、近似値、8バイト | 高精度な科学計算 |
FLOATやDOUBLEは近似値なので、計算誤差が発生します。金額や会計データには、必ずDECIMAL型を使いましょう。
符号なし(UNSIGNED)
整数型には、UNSIGNED(符号なし)をつけることができます。マイナスの値が不要な場合に使います。
- ✅ ID(主キー):マイナスのIDはありえない
- ✅ 年齢、在庫数、カウント数:マイナスにならない
- ✅ 範囲を2倍にしたい場合
📝 3. 文字列型の選択基準
主な文字列型
文字列を格納する型には、CHAR、VARCHAR、TEXTがあります。
| 型 | 特徴 | 用途 |
|---|---|---|
| CHAR(n) | 固定長文字列、常にnバイト使用 | 郵便番号、国コードなど固定長 |
| VARCHAR(n) | 可変長文字列、実際の長さ分だけ使用 | 名前、メールアドレス、タイトル |
| TEXT | 長い文字列、最大約64KB | 記事本文、説明文、コメント |
| MEDIUMTEXT | より長い文字列、最大約16MB | 非常に長い文章 |
CHAR vs VARCHAR
CHARとVARCHARの違いを具体例で見てみましょう。
VARCHAR のサイズ選定
基本原則:「必要十分な長さ」を設定する
- 名前:VARCHAR(100)
- メールアドレス:VARCHAR(255)
- 電話番号:VARCHAR(20)
- 郵便番号:CHAR(7) または VARCHAR(10)(ハイフンあり)
- URL:VARCHAR(2048)(URLの最大長)
- タイトル:VARCHAR(200)
TEXT型を使うタイミング
- 記事本文(ブログ、ニュースなど)
- 長い説明文
- コメント、レビュー
- JSON データ(大きい場合)
- インデックスが貼れない(または制限がある)
- ソートが遅い
- デフォルト値を設定できない
📅 4. 日付時刻型の違い
主な日付時刻型
日付や時刻を格納する型には、DATE、DATETIME、TIMESTAMPがあります。
| 型 | フォーマット | 範囲 | 用途 |
|---|---|---|---|
| DATE | YYYY-MM-DD | 1000年〜9999年 | 誕生日、期限 |
| TIME | HH:MM:SS | -838〜838時間 | 営業時間、所要時間 |
| DATETIME | YYYY-MM-DD HH:MM:SS | 1000年〜9999年 | 投稿日時、予約日時 |
| TIMESTAMP | YYYY-MM-DD HH:MM:SS | 1970年〜2038年 | 作成日時、更新日時 |
DATETIME vs TIMESTAMP
DATETIMEとTIMESTAMPは見た目は似ていますが、動作が異なります。
どちらを使うべきか?
TIMESTAMPを使う場合:
- ✅ 作成日時、更新日時(自動更新したい)
- ✅ ログのタイムスタンプ
- ✅ グローバルなシステム(タイムゾーン変換が必要)
DATETIMEを使う場合:
- ✅ イベント日時(タイムゾーン変換したくない)
- ✅ 予約日時
- ✅ 2038年以降のデータを扱う可能性
TIMESTAMPは、2038年1月19日以降の日付を扱えません。
理由:UNIX時間(1970年1月1日からの秒数)を32ビット整数で表現しているため。
対策:2038年以降のデータを扱う可能性がある場合はDATETIMEを使う
🎯 5. データ型選択の判断基準
データ型を選ぶときの質問フロー
データ型を選ぶときは、以下の質問に答えていくと適切な型が見つかります。
- 数値 → ステップ2へ
- 文字列 → ステップ3へ
- 日付・時刻 → ステップ4へ
- 小数点が必要?(金額、会計)→ DECIMAL
- 小数点が必要?(科学計算、誤差OK)→ FLOAT/DOUBLE
- 整数のみ? → 範囲に応じて TINYINT / SMALLINT / INT / BIGINT
- 長さが固定?(国コード、郵便番号など)→ CHAR(n)
- 長さが変動?(名前、メールなど)→ VARCHAR(n)
- 長い文章?(記事本文、説明文)→ TEXT
- 日付のみ?(誕生日など)→ DATE
- 時刻のみ?(営業時間など)→ TIME
- 日時で自動更新したい? → TIMESTAMP
- 日時で手動設定? → DATETIME
実践例:ユーザーテーブルの設計
実際に要件を見ながら、データ型を選んでみましょう。
⚙️ 6. テーブル作成時のオプション
CREATE TABLE文を書くとき、データ型以外にも設定すべき項目があります。初心者がつまずきやすいポイントを解説します。
AUTO_INCREMENT(自動採番)
AUTO_INCREMENT=データを挿入するたびに、自動的に1ずつ増える番号を振ってくれる機能
主キー(ID)に使うことで、INSERT時にIDを指定する必要がなくなります。
- IDの管理が楽(プログラムで番号を生成する必要がない)
- 重複しない一意の値が自動で付与される
- 削除しても番号は再利用されない(1, 2, 3を削除しても次は4)
ENGINE=InnoDB(ストレージエンジン)
ENGINE=MySQLがデータを保存・管理する仕組み(エンジン)を指定する
車で言えば、「ガソリンエンジン」か「電気モーター」かを選ぶようなものです。
| エンジン | 特徴 | 用途 |
|---|---|---|
| InnoDB | トランザクション対応、外部キー対応 | 現在の標準(迷ったらこれ) |
| MyISAM | 高速な読み取り、トランザクション非対応 | 読み取り専用のログテーブルなど |
- トランザクション:複数の処理を「全部成功」か「全部取り消し」にできる
- 外部キー制約:テーブル間の整合性を保証できる
- 行レベルロック:同時アクセスでも高速に処理できる
- クラッシュリカバリ:障害時にデータを復旧できる
DEFAULT CHARSET=utf8mb4(文字コード)
CHARSET(文字コード)=文字をどのように保存するかを決める設定
日本語や絵文字を正しく保存するために重要です。
MySQLの「utf8」は3バイト文字までしか対応していません。
絵文字(😀🎉👍)は4バイト文字なので、「utf8」では保存できません。
utf8mb4は4バイト文字に対応しているので、絵文字も正しく保存できます。
迷ったら、以下のテンプレートを使いましょう:
📝 STEP 4 のまとめ
- 整数型:TINYINT、SMALLINT、INT、BIGINT(サイズに応じて選択)
- 実数型:金額はDECIMAL、科学計算はFLOAT/DOUBLE
- 文字列型:固定長はCHAR、可変長はVARCHAR、長文はTEXT
- 日付時刻型:自動更新はTIMESTAMP、手動設定はDATETIME
- AUTO_INCREMENT:主キーに使うと自動で連番が振られる
- ENGINE=InnoDB:トランザクション・外部キー対応の標準エンジン
- CHARSET=utf8mb4:日本語・絵文字を正しく保存できる文字コード
・整数はINT
・文字列はVARCHAR
・日時はTIMESTAMP
から始めて、必要に応じて調整しましょう!
次のSTEP 5では、主キーと外部キーについて詳しく学び、テーブル間の関係を実装する方法を学びます!
📝 練習問題
「年齢」を格納するカラムに最適なデータ型を選んでください。
理由:
・年齢は0〜150程度の範囲
・TINYINT UNSIGNED は 0〜255 をカバー(十分)
・1バイトで済むので効率的
・マイナスの年齢はないので UNSIGNED
商品の価格(円単位、小数点あり)を格納するのに最適なデータ型を選んでください。
理由:
・金額は正確な値が必要(誤差が許されない)
・DECIMAL は固定小数点数で正確
・DECIMAL(10, 2) = 最大99,999,999.99円
・FLOATやDOUBLEは誤差が発生するので不適切
メールアドレスを格納するのに最適なデータ型を選んでください。
理由:
・メールアドレスは可変長(人によって長さが違う)
・RFC標準では最大254文字(255で十分)
・CHAR は無駄なスペースを使うので不適切
・TEXT は大きすぎる&インデックスに制限
郵便番号(例:123-4567)を格納するのに最適なデータ型を2つ挙げてください。
方法1:CHAR(8)(ハイフンあり「123-4567」)
方法2:CHAR(7)(ハイフンなし「1234567」)
理由:どちらも固定長なので CHAR が適切。VARCHAR(10) でも可能だが、固定長データには CHAR の方が効率的。
ブログ記事の本文を格納するのに最適なデータ型を選んでください。
理由:
・記事本文は長いテキスト(数千〜数万文字)
・TEXT: 最大65,535文字(約64KB)← 通常のブログ記事なら十分
・MEDIUMTEXT: 最大16,777,215文字(約16MB)← 非常に長い記事
・一般的には TEXT で十分
「作成日時」と「更新日時」を自動管理したい場合、どのように定義しますか?
理由:
・TIMESTAMP は自動更新が可能
・created_at: レコード作成時に自動設定
・updated_at: レコード更新時に自動更新
なぜ金額を格納するのに FLOAT ではなく DECIMAL を使うべきですか?
FLOAT/DOUBLE は浮動小数点数で「近似値」を保存するため、計算誤差が発生するからです。
金額や会計データなど、誤差が許されないデータには必ず DECIMAL を使いましょう。
以下のテーブル設計の問題点を3つ以上指摘してください。
- product_id VARCHAR(50)
→ IDは通常 INT UNSIGNED AUTO_INCREMENT が適切 - product_name VARCHAR(10000)
→ 商品名に10000文字は過剰。VARCHAR(200)程度で十分 - price FLOAT
→ 金額は DECIMAL を使うべき(誤差が発生する) - stock_quantity VARCHAR(100)
→ 在庫数は整数なので INT UNSIGNED が適切 - created_at VARCHAR(255)
→ 日時は TIMESTAMP または DATETIME を使うべき
❓ よくある質問
Q1: VARCHAR の長さは、どこまで細かく設定すべきですか?
「必要十分な長さ」を設定しましょう。厳密に最小限にする必要はありませんが、極端に大きくするのも避けましょう。
後から拡張するのは簡単ですが、縮小は既存データに影響するので、最初は少し余裕を持たせてOKです。
Q2: CHAR と VARCHAR、どちらを使うか迷ったらどうすればいいですか?
迷ったら VARCHAR を使いましょう。CHAR は固定長なので、長さが変動するデータには無駄が多いです。
CHAR を使うのは、国コード(2文字)、郵便番号(7文字)、MD5ハッシュ(32文字)など、長さが完全に固定のデータのみです。
Q3: INT と BIGINT、どちらを選ぶべきですか?
基本的には INT で十分です。INT UNSIGNED は 0〜約42億 の範囲を持ち、ほとんどのケースで十分です。
BIGINT を使うのは、42億を超える可能性がある場合(SNSのいいね数、大量データのIDなど)のみです。
Q4: TIMESTAMP と DATETIME、結局どちらを使えばいいですか?
用途によって使い分けましょう。
- created_at、updated_at(自動更新したい)→ TIMESTAMP
- イベント日時、予約日時(固定したい)→ DATETIME
Q5: データ型は後から変更できますか?
可能ですが、データ量が多いと大変です。ALTER TABLE でデータ型を変更できますが、データ量が多いと時間がかかり、テーブルロックが発生する場合もあります。
そのため、最初に適切な型を選ぶことが重要です。
学習メモ
データベース設計・データモデリング - Step 4