VARCHAR徹底解説:MySQL・PostgreSQL・SQL Server・Oracleの実装差、ストレージ&パフォーマンス、設計時の注意点

はじめに — VARCHAR型とは何か

SQLにおける VARCHAR(可変長文字列、一般には「varchar型」)は、格納する文字列の長さが可変である文字列型です。固定長の CHAR と対比され、格納時に実際の文字数に応じてディスク/メモリが割り当てられるため、同じ長さのデータでも無駄な空白を減らせるのが特徴です。本コラムでは、SQL標準と主要なRDBMS(MySQL、PostgreSQL、SQL Server、Oracle)の実装差、ストレージやパフォーマンス、注意点、運用上のベストプラクティスまでを詳しく解説します。

SQL標準における表記と基本仕様

  • SQL標準では VARCHAR(n)CHARACTER VARYING(n) として定義され、通常「n は文字数」を意味します(文字集合に依存)。

  • 可変長であるため、実際に格納されるのは文字列の文字数(とそのエンコーディングに応じたバイト列)で、型自身は末尾の空白でパディングしません(これが CHAR との主な違い)。

主要なDBMSごとの違い(実務で押さえるべき点)

MySQL

  • VARCHAR(n) の n は文字数を意味します(MySQL 5.0.3以降)。ただし、実際の格納バイト数は文字セット(例:utf8mb4は最大4バイト/文字)に依存します。

  • ストレージは文字列長に応じて可変で、文字列長を示すオーバーヘッドとして 1 または 2 バイトが使われます(最大長が255以下かどうかで変わるなど)。

  • 行長やインデックスの制限(InnoDBの行サイズやインデックスのバイト長制限)に注意が必要です。特にutf8mb4のようなマルチバイト文字を使う場合、インデックスで使えるプレフィックス長が制限されることがあります。

PostgreSQL

  • varchar(n) は長さ制約を課す点で存在しますが、内部的には text と同じく可変長の扱いで、長さ制約はチェックとして実装されています(つまり機能面で大きな差は少ない)。

  • 非常に大きな値はTOASTという仕組みで外部に格納されるため、実務上の「ほぼ無制限」の文字列を扱えます。

Microsoft SQL Server

  • varchar(n) は最大 n = 8000(バイト)まで指定でき、Unicodeを扱う場合は nvarchar(n)(最大 4000 文字、内部的に2バイト/文字)を使うか、varchar(max) / nvarchar(max) を使います。

  • varchar(max) は大きな文字列を格納するためのLOB相当で、通常の行内格納か外部格納(LOB)されます。

Oracle

  • Oracleでは主に VARCHAR2(n) が使われます。SQLレベルでは通常 VARCHAR2 の最大は 4000 バイト(または文字)ですが、PL/SQLではより大きい(32767バイト)など実行環境に差があります。

  • Oracleはデフォルトで長さ単位がBYTEかCHARかを設定でき、マルチバイト文字セットの場合は VARCHAR2(100 CHAR) のように明示的に文字単位指定が推奨されます。

  • 注意点として、Oracleは空文字列('')を NULL と扱うという特殊挙動があります(アプリ側で空文字とNULLを区別したい場合は注意)。

ストレージとパフォーマンスの実務的理解

  • 可変長ゆえのオーバーヘッド:どのDBMSでも長さを管理するためのヘッダー(数バイト)が付きます。MySQLでは1/2バイト長ヘッダ、PostgreSQLではvarlenaヘッダ等が使われます。

  • ディスク/メモリ効率:短い文字列が多い場合は VARCHAR が有利。逆に常にほぼ同じ長さであれば CHAR の方が処理が速い場合があります(行のオフセットが固定されるため)。

  • インデックス:長い VARCHAR をインデックス化すると、インデックスサイズが増え検索が遅くなるか、インデックス作成自体に上限(MySQL/InnoDBのバイト長制限など)がある点に注意。

  • 文字セットの影響:utf8mb4のような可変バイト文字エンコーディング使用時は、宣言した文字数を格納するために必要なバイト数が増えるため、DDLで指定する「n」は文字数で扱うよう注意(DBMSによってはデフォルトがバイト単位である場合あり)。

挙動の差による落とし穴と回避策

  • 空文字とNULLの扱い:Oracleでは空文字がNULLになる(他DBと挙動が異なる)。アプリでは明示的にNULL/空文字を区別するロジックを入れるか、DB側で制約を設ける。

  • トリミング/比較の差:DBMSや照合順序(collation)によって文字列比較時の挙動が変わる(大文字小文字、アクセント、末尾スペースの扱い等)。テストと仕様確認が必須。

  • DDLの「n」の単位:Oracle等ではBYTE/CHAR指定があるので多バイト環境では VARCHAR2(100 CHAR) のように明記することをおすすめします。

  • インジェクション対策:文字列型だからといってSQLインジェクションの対策を怠らない。常にパラメータ化されたクエリやプレースホルダを使用しましょう。

いつ VARCHAR を使うべきか、代替は何か

  • 使うべき場面:長さが不定で短〜中程度(数十〜数千文字)の文字列を扱う列(例:名前、メールアドレス、ステータスフラグ、説明文など)。

  • 代替:非常に長い自由テキストは TEXT/CLOB を使う。Unicodeが必要な場合は nvarchar(SQL Server)やDBの文字セットをUTF-8/UTF-16にする。

  • 正規化を検討:繰り返し現れる長い文字列は別テーブルに分けて参照することでインデックス効率や更新コストを改善できる。

マイグレーションや設計時のチェックリスト(実践的)

  • 想定最大文字長を決める(過剰に大きくしすぎない)。

  • 文字セット/照合順序を統一する(utf8mb4 + 適切な照合順序が推奨されることが多い)。

  • DBMSごとのサイズ上限(VARCHARの最大指定値、インデックス長制限、行サイズ制限)を確認する。

  • 空文字/NULLの扱い、末尾スペース挙動をアプリと合わせる。

  • 長いカラムを頻繁に検索・ソートする場合はインデックス設計を検討(プレフィックスインデックスや全文検索の導入など)。

具体例(簡易DDL)

例:ユーザ名(最大100文字)、説明(可変長、大きめ)

  • MySQL: <code>CREATE TABLE users (username VARCHAR(100) CHARACTER SET utf8mb4, description TEXT);</code>

  • PostgreSQL: <code>CREATE TABLE users (username VARCHAR(100), description TEXT);</code>

  • SQL Server: <code>CREATE TABLE users (username VARCHAR(100), description VARCHAR(MAX));</code>

  • Oracle: <code>CREATE TABLE users (username VARCHAR2(100 CHAR), description CLOB);</code>

まとめ(実務的要点)

VARCHARは可変長で柔軟かつ効率的に文字列を格納できるため、RDB設計で最もよく使われる型の一つです。ただし「文字数かバイト数か」「DBMS固有の上限や挙動差」「文字セットや照合順序」「インデックス制限」など実装差に起因する落とし穴が複数あります。設計時には使用するDBMSのドキュメントを確認し、文字セットを統一、必要であればCHAR/byte単位の明示、長さチェックやインデックス設計を怠らないことが重要です。

参考文献