CHAR型とは何か?固定長文字列の基礎からDBMS別の挙動・パディング、文字数とバイト数の違いを徹底解説
はじめに — 「CHAR型」とは何か
IT(特にデータベース)における「CHAR型」は、文字列を格納するための基本的なデータ型の一つで、「固定長の文字列」を扱うことを前提に設計されています。VARCHAR のような可変長文字列型と対になる概念で、定義した長さに満たない場合はスペースで埋めて格納する(右側にパディングする)のが一般的な振る舞いです。ただし、具体的な仕様や挙動(パディングの有無、比較時の扱い、内部的なバイト数計算など)はデータベース製品ごとに差があるため、実運用時には製品ドキュメントを確認する必要があります。
基本的な概念
- 固定長:CHAR(n) は「n 文字分」を常に占有する。実際に格納する文字列が短ければ空白文字(スペース)で右側を埋める。
- 用途:コード類(国コード、状態コード、ハッシュの固定長表現など)や、長さが固定で短いデータに向く。
- 注意点:文字数とバイト数の違い(特にマルチバイト文字・UTF-8 環境)や、DBMSごとの比較・トリミングルールに注意する。
SQL標準の考え方と実装差
SQL 標準では、CHAR(または CHARACTER)は固定長文字列であり、短い値はスペースでパディングされるとされています。また、標準では文字列比較の際に末尾の空白は無視される(パディングが比較結果に影響しない)とする規定があります。ただし、実務で使う主要な DBMS(MySQL、PostgreSQL、SQL Server、Oracle 等)はそれぞれ細かい実装差や注意点を持っています。
主要なデータベース製品ごとの挙動(概要)
- MySQL:
CHAR は固定長で右パディングされる(格納時にスペースで埋められる)。CHAR と VARCHAR の長さ指定は「文字単位(character)」で行われる(文字セットに依存し、例えば utf8mb4 なら最大 4 バイト/文字となり得る)。文字数とバイト数を調べる関数は CHAR_LENGTH(文字数)と LENGTH(バイト数)を使い分ける。
- PostgreSQL:
character(n)(CHAR(n))は、固定長の文字列で、必要に応じて右側がスペースで埋められる。内部では文字列長は文字単位で扱われ、length(text) は文字数を返す。挙動はほぼ SQL 標準準拠であるが、注意すべき実装固有の振る舞いもある。
- SQL Server(Microsoft):
char(n) は固定長で、n はバイト数(非 Unicode)を意味する。Unicode 用の固定長は nchar(n) で、こちらは UTF-16 系の内部表現(2 バイト/文字)を使う。関数 LEN は末尾のスペースを無視して文字数を返す(DATALENGTH はバイト数を返す)などの注意点がある。
- Oracle:
CHAR は固定長で、最大長は製品バージョンや設定によるが一般に比較的短め。Oracle も格納時に右パディングを行い、比較時には末尾スペースを無視する(SQL 標準に近い)。
(詳細な仕様や最大長の制約は DBMS のバージョンや設定によるため、導入時には必ず公式ドキュメントを参照してください。)
「文字数」と「バイト数」— なぜ混乱が起きるのか
多くの問題は「CHAR(n) の n が示すのは文字数かバイト数か」という点から生じます。近年主流の UTF-8 のような可変バイト長のエンコーディングを使うと、1 文字が 1 バイト以上を占めるため、同じ n でも必要なストレージ量が変わります。
- MySQL(現行の多くの設定):CHAR(n) は「最大 n 文字」として扱われるが、内部的な領域は n × max_bytes_per_char (charset により異なる)に確保されることがある。例えば utf8mb4 は最大 4 バイト/文字なので、CHAR(10) utf8mb4 は 40 バイト分を確保する可能性がある。
- SQL Server の char(n) は非 Unicode の場合バイト数指定、nchar(n) は文字数(だが内部は UCS-2/UTF-16 で 2 バイト/文字)という違いがある。
- 文字数を得る関数とバイト数を得る関数を正しく使い分ける(例:MySQL の CHAR_LENGTH vs LENGTH、SQL Server の LEN vs DATALENGTH、PostgreSQL の length(text) と OCTET_LENGTH)ことが重要。
スペース(パディング)と比較の挙動
CHAR は固定長のため、短い文字列はスペースで右詰めにされることが多いです。これに関して重要な点:
- SQL 標準では、文字列比較の際に末尾の空白は無視される('abc' = 'abc ' は true)。多くの DBMS はこの仕様に従いますが、挙動の細部(例えばストレージにスペースを保持するかどうか、レプリケーションやバイナリ比較の挙動)は異なる。
- バイナリ比較(BINARY 型や COLLATE でバイナリ照合を指定した場合)や、プログラム側でバイト列として扱う場合は、末尾スペースが差異となることがあるので注意が必要です。
- SQL Server の LEN 関数は末尾のスペースを除いて文字数を返す(つまり LEN('a ') = 1)が、DATALENGTH はバイト数を返し末尾スペースも含む。
NCHAR / NVARCHAR と Unicode 対応
多くの DBMS は国際化対応として NCHAR / NVARCHAR を提供しています。これらは「National character set」(多くは Unicode)を使う固定長/可変長の文字列型です。
- SQL Server の nchar(n)/nvarchar(n) は UTF-16(UCS-2)ベースで、文字あたり固定 2 バイトとなる(ただしサロゲートなどの扱いに注意)。
- Oracle の NCHAR は NLS_NCHAR_CHARACTERSET に基づき、データベースの文字セットとは別の文字セットで格納されることがある。
- MySQL は NCHAR synonym の扱いや CHARACTER SET 指定で Unicode(utf8/utf8mb4)を選択できる。CHAR にも CHARACTER SET を指定可能。
パフォーマンスとディスク効率
CHAR の固定長性は利点と欠点を持ちます。
- 利点:行内のオフセット計算が単純になり、固定長列が多いテーブルではパフォーマンスやメモリ効率に有利になることがある。インデックスも列サイズが一定だと効率的。
- 欠点:可変長データを無理に CHAR にすると無駄な空白領域を保存してしまいディスク/メモリの浪費になる。特に multi-byte charset の場合は想定以上にバイト数が増える。
- ハッシュ値(MD5、SHA 等)や UUID の格納:文字列で表した場合は CHAR(32) や CHAR(36) を使うことがあるが、より効率的には BINARY(16)(生のバイナリ)で保存する方がサイズ・比較ともに有利。
実務でのベストプラクティス
- データが真に固定長(国コード、状態コード、固定桁の識別子など)なら CHAR を検討する。そうでなければ VARCHAR の方が無駄が少ない。
- 国際化が必要なら最初から Unicode(utf8mb4、NCHAR など)を選ぶ。文字数とバイト数の違いを把握し、必要ならバイト数上限で余裕を持った設計をする。
- ハッシュや UUID は可能ならバイナリ型(BINARY/VARBINARY)で保存して比較・インデックスを効率化する。
- 比較時の末尾空白の挙動、照合順序(COLLATION)、ケースセンシティビティ(大文字小文字の区別)などを想定してクエリやインデックス設計を行う。
- 既存システムを移行する際は、CHAR のパディングや DBMS 間の文字列比較の違いが原因でバグが出やすいので、留意してテストする。
具体的な例(SQL)
以下は MySQL を想定した簡単な例です(他 DBMS でも概念は同じですが詳細は差があるので注意)。
CREATE TABLE sample (
code CHAR(3) CHARACTER SET latin1, -- 固定長 3 文字
name VARCHAR(100) CHARACTER SET utf8mb4
);
INSERT INTO sample (code, name) VALUES ('JP', 'Japan'); -- code は右側がスペースでパディングされる
SELECT CHAR_LENGTH(code), LENGTH(code) FROM sample; -- CHAR_LENGTH は文字数、LENGTH はバイト数
よくある誤解と落とし穴
- 「CHAR(n) は常に n バイトを取る」:マルチバイト文字セットでは false(DBMS と文字セットによる)。
- 「末尾スペースは必ず保存されない/常に無視される」:保存・比較・関数による扱いは DBMS による差異があるため、一律の前提は危険。
- 「VARCHAR より常に遅い/早い」:一概には言えず、データ特性(長さ分布、文字セット)や DBMS の内部実装に依存する。
まとめ
CHAR 型は「固定長文字列」を扱うための基本的なデータ型で、適切に使えば性能や単純さの面で有益です。しかし、文字数とバイト数、文字セット(Unicode)の影響、DBMS 間のスペース処理や比較の差異といった点で思わぬ問題が発生しやすいです。設計段階ではデータの性質(固定長かどうか、ASCII だけか、多言語対応か)、運用上の検索・インデックス要件、そして使う DBMS の仕様をよく理解し、必要ならドキュメントを参照して正しく選択しましょう。
参考文献
- MySQL 8.0 リファレンスマニュアル - CHAR と VARCHAR
- MySQL - The utf8mb4 Character Set
- PostgreSQL ドキュメント - 文字列型
- Microsoft SQL Server - char と varchar (Transact-SQL)
- Microsoft SQL Server - LEN (Transact-SQL)
- Microsoft SQL Server - DATALENGTH (Transact-SQL)
- Oracle Database ドキュメント - データ型
- PostgreSQL - 文字列長に関する関数(length, octet_length 等)


