VARCHAR徹底解説:仕様・性能・DBMS別挙動と実践的ベストプラクティス

VARCHARとは何か — 基本概念

VARCHARはリレーショナルデータベースで広く使われる可変長の文字列型です。固定長のCHARと違い、実際に格納される文字数に応じて必要なバイト数だけを使うため、短い文字列が多いカラムでディスクやメモリを節約できます。一方で可変長であることが処理やインデックスに影響を与えるため、用途に応じた理解が重要です。

仕様とストレージの基本

一般にVARCHARは次のような特徴を持ちます。

  • 宣言時に最大長を指定する(例:VARCHAR(100))。最大長の単位はDBMSや設定で「文字(characters)」か「バイト(bytes)」になる。
  • 格納時は実データ長に加え、長さを示すプレフィックス(1バイトまたは2バイトなど)を保存する。
  • 可変長のため、実行時に行サイズが変化し、ページ分割やTOAST/overflow格納の挙動に影響する。

具体的な保存方法や上限はDBMSごとに異なります。以下で主要なDBMSの挙動を整理します。

MySQLにおけるVARCHAR

MySQLでは、VARCHARは可変長で格納され、宣言時の最大バイト数・文字数は複数の要因に依存します。重要ポイントは次のとおりです。

  • 長さプレフィックスは、宣言長が255バイト以下なら1バイト、それを超えると2バイトを使用する。
  • テーブルの1行あたりの最大バイト数は65,535バイトだが、実際は行内のオーバーヘッドや他カラムとの兼ね合いで制約される。文字セット(utf8mb4など)の最大バイト数/文字を考慮する必要がある。
  • InnoDBのROW_FORMATがDYNAMICまたはCOMPRESSEDなら、長いVARCHARは行外(オーバーフロー領域)に格納され、行内には20バイト程度のポインタだけが残る。これにより非常に長い値でも行サイズ制限の影響を軽減できる。
  • インデックスに対する制約として、インデックス長の上限があり、utf8mb4ではプレフィックスインデックスを使って一部をインデックス化する必要がある場合がある(例:MySQLの一部設定で767バイト制限など)。

PostgreSQLにおけるVARCHAR

PostgreSQLではCHARACTER VARYING(n)やVARCHAR(n)が使えますが、実装上はTEXTと同じ可変長格納で、サイズ制約だけが追加されたチェックとして扱われます。大型値はTOAST(The Oversized-Attribute Storage Technique)により行外に格納されます。事実上、パフォーマンス面ではTEXTと差がないため、長さ制約が不要ならTEXTを選ぶことが多いです。

SQL ServerにおけるVARCHAR

SQL ServerでのVARCHARはバイトベースでの制限があり、通常は最大8000バイトまで指定可能です。より大きな文字列を扱う場合はVARCHAR(MAX)を使い、これは最大2GB相当のデータを格納できます。内部的には可変長で、長さを示す2バイトプレフィックスがあります。Unicodeを扱う場合はNVARCHAR(2バイト/文字)を使う点に注意してください。

OracleにおけるVARCHAR2

OracleではVARCHAR2が一般的に用いられ、VARCHARは非推奨です。SQLの最大は伝統的に4000バイト(または文字)でしたが、近年の設定やバージョン(拡張オプション)では更に大きな値を使えるケースがあります。Oracleはバイト単位か文字単位かを設定で切り替えられるため、マルチバイト文字セットの扱いに注意が必要です。

CHAR / TEXT / NVARCHARとの比較

主要な差分をまとめます。

  • CHAR: 固定長。短いが同一長のデータが多い場合は処理が速く、パディング(空白埋め)される。無駄な空白が発生する。
  • VARCHAR: 可変長。ストレージ効率が良いが、行の可変性がキャッシュやインデックスの振る舞いに影響する。
  • TEXT/BLOB: 非常に長いデータ向け。多くのDBでインデックスや操作に制約があり、全文検索や専用型(JSON型等)が有利なケースもある。
  • NVARCHAR: SQL ServerなどでUnicodeを確実に扱う型。バイト数が増えるためサイズ見積りに注意。

文字セット・照合順序(charset/collation)の影響

VARCHARの宣言長が「文字数」か「バイト数」かはDBMSと設定によるため、マルチバイト文字セット(例:utf8mb4)を使う場合は必ず最大バイト数を想定してください。また、照合順序により大文字小文字の扱いや比較結果が変わります。ユニーク制約やインデックスを設計する際は照合順序とインデックス長の関係を確認することが重要です。

インデックスとパフォーマンス考慮

VARCHARに対するインデックスは強力ですが、長すぎるカラムをフルにインデックス化するとインデックスサイズが肥大化して性能が低下します。対策:

  • 適切な長さ制限を設ける(現実的な最大長)。
  • 長い文字列はプレフィックスインデックスを用いる(DBMSがサポートする場合)か、ハッシュ列を作って索引する。
  • 全文検索には専用の全文検索エンジン(MySQLのFULLTEXT、PostgreSQLのGIN/tsvector、Elasticsearchなど)を検討する。

セキュリティと入力検証

VARCHARを使う際でもSQLインジェクションや過長入力に対する検証は必須です。パラメタライズドクエリやプリペアドステートメントを用いてSQLインジェクションを防ぎ、長さチェックをアプリ側とDB側(CHECK制約や最大長)で二重に行うと安全性が向上します。パスワードはハッシュ化して長さ固定のバイナリ格納(BINARYやVARBINARY)を検討します。

運用上の注意点(ALTERやマイグレーション)

カラム長の拡張や型変更は大きなテーブルではコストが高くなる場合があります。MySQLの古いバージョンではALTER TABLEでテーブル再作成が発生することがあり、ダウンタイムを招くことがあります。近年のDBMSはオンラインDDLやコピー不要の変更をサポートしますが、事前にバージョンごとの振る舞いを調査してから実行してください。

実践的なベストプラクティス

  • 必要最小限の長さを指定する。過剰な余裕はインデックス肥大化や無駄なメモリ使用につながる。
  • Unicodeが必要ならSQL ServerならNVARCHAR、MySQLではutf8mb4を使い、文字数とバイト数の違いを意識する。
  • 可変長だが短い文字列(メールアドレス、ユーザー名等)はVARCHARで。大量の長文はTEXT/LOBや専用型を検討。
  • インデックスを貼る場合はカーディナリティを見極め、プレフィックスインデックスやハッシュを活用する。
  • アプリとDBの両方で長さや文字種のバリデーションを行い、データ整合性を確保する。

実例:よくある設計例

ユーザー名:VARCHAR(50)(実際の上限を考えて50文字程度)

メールアドレス:VARCHAR(254)(RFCに基づく最大長を参考)

コメントや投稿本文:TEXTまたはVARCHAR(MAX)(検索や集計方針で決定)

よくある誤解と注意点

「VARCHARは常に速い」「VARCHARは文字数制限が厳密に必要」というような単純化は危険です。DBMSの内部実装や設定(文字セット、ストレージエンジン、行フォーマット)によって実際の挙動は大きく変わります。設計段階で想定されるデータの性質(長さ分布、検索頻度、更新頻度、インデックス要否)を元に判断してください。

まとめ

VARCHARはほとんどのアプリケーションで中心的に使われる柔軟な文字列型です。ただし、文字セット、DBMS固有の保存方法、インデックス制約、長さの扱いなどを正しく理解することが高性能かつ安全なシステム構築には不可欠です。実運用では短い文字列はVARCHAR、長文はTEXT/LOBや全文検索を組み合わせ、必要に応じてオンラインDDLや検証ルールで運用リスクを下げることを推奨します。

参考文献

MySQL 8.0: String Type Overview
MySQL 8.0: CHAR and VARCHAR
MySQL 8.0: InnoDB Row Format
PostgreSQL: Character Types
PostgreSQL: TOAST
Microsoft SQL Server: CHAR and VARCHAR (Transact-SQL)
Oracle Database: Data Types (VARCHAR2)
MySQL: utf8mb4 and Unicode Support