> ## Documentation Index
> Fetch the complete documentation index at: https://villagesql.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# MySQL のデータ型の選択

> 列に適した MySQL のデータ型を選ぶ方法: 整数、文字列、日付、および JSON — ストレージコストとパフォーマンスのトレードオフを添えて。

> [card] [VillageSQL is a drop-in replacement for MySQL with extensions.](https://villagesql.com/docs/en/8.4/stable/install-server.md)
>
> All examples on this page work on VillageSQL. Install Now →

列に割り当てるデータ型は、ストレージサイズ、インデックスの効率、およびクエリの動作に影響します。必要以上に大きな型を選ぶと、すべての行と、その列を含むすべてのインデックスで領域が無駄になります。小さすぎる型を選ぶと、切り捨てエラーや、黙って起きるデータ損失につながります。

## 整数型

MySQL には 5 つの整数型があります。想定される範囲に収まる最小の型を選んでください。

| 型 | ストレージ | 範囲（符号付き） | 使う場面 |
| :- | :- | :- | :- |
| `TINYINT` | 1 バイト | -128 〜 127 | フラグ、ステータスコード、小さな列挙 |
| `SMALLINT` | 2 バイト | -32,768 〜 32,767 | 約 32K を超えないカウントや ID |
| `MEDIUMINT` | 3 バイト | -830 万 〜 830 万 | 中規模の ID やカウンター |
| `INT` | 4 バイト | -21 億 〜 21 億 | ほとんどの ID とカウンター |
| `BIGINT` | 8 バイト | ±920 京 | 大きな ID、ミリ秒単位の Unix タイムスタンプ |

`INT UNSIGNED` は正の範囲を約 43 億に倍増させます。常に正の値をとる主キーと外部キーには `UNSIGNED` を使ってください。追加コストなしで範囲を広げられます。

`BIGINT` は `INT` の 2 倍のストレージを使います。すべての ID にデフォルトで使ってはいけません。`INT` は 20 億行以上を扱えますが、ほとんどのテーブルはそこまで到達しません。

## 文字列型

### VARCHAR と CHAR

`VARCHAR(n)` は、文字列に含まれるバイト数（に長さのための 1〜2 バイトを加えたもの）だけを格納します。`CHAR(n)` は常にちょうど `n` バイトを格納し、短い文字列はスペースで埋めます。

| 型 | ストレージ | 使う場面 |
| :- | :- | :- |
| `CHAR(n)` | 常に n バイト | 固定長の文字列（国コード、'Y'/'N' のようなステータスフラグ、MD5 ハッシュ） |
| `VARCHAR(n)` | 実際の長さ + 1〜2 バイト | 可変長の文字列（名前、メールアドレス、URL） |

`CHAR` は、長さのプレフィックスを解析する必要がないため、固定長の値ではわずかに速いことがあります。長さが変わるものには `VARCHAR` を使ってください。

### VARCHAR と TEXT

```sql theme={null}
-- VARCHAR stores inline in the row (up to row size limit)
name VARCHAR(255)

-- TEXT stores off-page once it exceeds a threshold; inline storage is limited
description TEXT
```

行サイズの上限までの `VARCHAR` 値は、クラスタ化インデックスのページ内にインラインで格納されます。`TEXT`（および `BLOB`）の値は、十分に大きくなるとオーバーフローページに格納されます。これは次のことを意味します。

* `VARCHAR` 列は直接インデックスに含められる
* `TEXT` 列は完全にはインデックス化できない — プレフィックス長が必要: `INDEX (description(100))`

数百文字未満だと分かっている文字列には `VARCHAR` を使ってください。インライン格納が意味をなさない長い内容（記事、コメント、HTML）には `TEXT` を使います。

## 日付と時刻の型

| 型 | ストレージ | 範囲 | 使う場面 |
| :- | :- | :- | :- |
| `DATE` | 3 バイト | 1000-01-01 〜 9999-12-31 | 時刻なしの日付のみ |
| `TIME` | 3 バイト | -838:59:59 〜 838:59:59 | 経過時間または時刻 |
| `DATETIME` | 8 バイト | 1000-01-01 〜 9999-12-31 | タイムゾーン変換のないタイムスタンプ |
| `TIMESTAMP` | 4 バイト | 1970-01-01 〜 2038-01-19 | 自動更新されるタイムスタンプ。UTC で格納され、セッションのタイムゾーンで表示される |
| `YEAR` | 1 バイト | 1901 〜 2155 | 年のみ |

`DATETIME` と `TIMESTAMP` の重要な違いは次のとおりです。

* `TIMESTAMP` は値を UTC として格納し、取得時にセッションの `time_zone` に変換します。アプリケーションが複数のタイムゾーンで動作する場合、`TIMESTAMP` は変換を自動的に処理します。
* `DATETIME` はタイムゾーン変換なしでリテラル値を格納します。入れたものがそのまま出てきます。
* `TIMESTAMP` には 2038 年の上限があります（Unix タイムスタンプのオーバーフロー）。2038 年以降の日付には `DATETIME` を使ってください。

```sql theme={null}
-- TIMESTAMP auto-updates on insert and update
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
```

タイムゾーンの扱いの詳しい説明については、[MySQL のタイムスタンプとタイムゾーン](https://villagesql.com/docs/ja/guides/timestamps-timezones.md)を参照してください。

## 10 進数と浮動小数点

| 型 | ストレージ | 精度 | 使う場面 |
| :- | :- | :- | :- |
| `DECIMAL(p,s)` | 可変 | 正確 | 金額、金融計算 — 通貨には決して FLOAT を使わない |
| `FLOAT` | 4 バイト | 約 7 桁の有効数字 | 近似値で許容される科学データ |
| `DOUBLE` | 8 バイト | 約 15 桁の有効数字 | より高精度な近似値 |

`FLOAT` と `DOUBLE` は 2 進浮動小数点を使うため、10 進の小数を正確に表現できません。浮動小数点では `0.1 + 0.2` は `0.30000000000000004` になります。金額には常に `DECIMAL` を使ってください。

```sql theme={null}
-- Correct: exact decimal arithmetic
price DECIMAL(10, 2)   -- up to 99,999,999.99

-- Wrong: floating-point rounding errors will appear in financial calculations
price FLOAT
```

## JSON

`JSON` 列は検証済みの JSON を格納し、パスベースのクエリ演算子を提供します。

```sql theme={null}
-- Store structured data without a fixed schema
CREATE TABLE events (
    id      INT PRIMARY KEY AUTO_INCREMENT,
    payload JSON NOT NULL
);

-- Extract a field
SELECT payload->>'$.user_id' FROM events;

-- Filter on a nested field
SELECT * FROM events WHERE payload->>'$.event_type' = 'purchase';
```

`JSON` 列には直接インデックスを作成できません。頻繁にクエリされる JSON フィールドにインデックスを作成するには、生成列を使います。

```sql theme={null}
ALTER TABLE events
    ADD COLUMN event_type VARCHAR(50) AS (payload->>'$.event_type') STORED,
    ADD INDEX idx_event_type (event_type);
```

## よくある質問

#### 主キーには INT と BIGINT のどちらを使うべきですか?

`INT` は符号付き整数で 21 億行、符号なしで 43 億行を扱えます。ほとんどのテーブルでは `INT UNSIGNED` で十分です。それを本当に超えると予想される場合、または 4 バイトに収まらない UUID 形式の ID を使っている場合は `BIGINT` を使ってください。

#### 考えずに済むように、どこでも VARCHAR(255) を使ってもよいですか?

可能ですが、`VARCHAR` の宣言が長いほどインデックスキーが広くなり、インデックスのメモリ使用量が増え、1 ページに収まるインデックスエントリの数が減ります。現実的な最大値を宣言してください。名前のフィールドなら `VARCHAR(255)` ではなく `VARCHAR(100)` です。実際のストレージコストはデータの長さに一致しますが、インデックスキーの長さは宣言したサイズで固定されます。

#### NULL とデフォルト値の実際の違いは何ですか?

`NULL` は「不明」を意味します。式を通じて伝播し、集計関数からは除外されます。`0` や `''` のようなデフォルト値は「明示的に空に設定された」ことを意味します。本当にデータが存在しない場合には `NULL` を、列にすぐ妥当な値を持たせたい「未設定」のシナリオではデフォルト値を選んでください。両者を混在させると、クエリに一貫性のなさが生じます。

## トラブルシューティング

| 問題 | 解決策 |
| :- | :- |
| `Data too long for column` | 列の型が狭すぎます。`VARCHAR` の長さを増やすか、`TEXT` に切り替えます |
| 金融計算での丸め誤差 | `FLOAT`/`DOUBLE` を `DECIMAL(p,s)` に置き換えます |
| `TIMESTAMP` が誤った時刻を表示する | セッションの `time_zone` が想定と異なります。`SELECT @@session.time_zone` で確認します |
| TEXT 列にインデックスを作成できない | プレフィックスインデックス `INDEX (col(100))` を使うか、生成列を追加します |
| INT の主キーが上限に近づいている | 上限に達する前に `BIGINT` または `INT UNSIGNED` に変更します |

## 関連項目

* [MySQL の正規化](https://villagesql.com/docs/ja/guides/normalization.md) — 型の決定のためのスキーマ設計の背景
* [MySQL の JSON](https://villagesql.com/docs/ja/guides/json-in-mysql.md) — 厳格なスキーマの柔軟な代替としての JSON 列型
* [MySQL のインデックスの仕組み](https://villagesql.com/docs/ja/guides/mysql-indexes.md) — データ型の選択はインデックスのサイズと効率に影響する
* [多次元の範囲クエリ](https://villagesql.com/docs/ja/guides/cube-queries.md) — n 次元の幾何データを格納してクエリするための cube 型
* [MySQL と PostgreSQL: どちらを使うべきか?](https://villagesql.com/docs/ja/guides/mysql-vs-postgresql.md) — 2 つのデータベースが型などでどう異なるか
* [MySQL の utf8mb4: 絵文字と完全な Unicode の格納](https://villagesql.com/docs/ja/guides/utf8mb4.md) — 列の文字セットと 4 バイトの現実
* [MySQL の本物のブール型](https://villagesql.com/docs/ja/guides/boolean-columns.md) — true と false 以外のすべてを拒否する列型
* [MySQL SELECT](https://villagesql.com/docs/ja/tutorial/select.md) — これらの列を読み戻すチュートリアルのレッスン


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.