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 の仕様をよく理解し、必要ならドキュメントを参照して正しく選択しましょう。

参考文献