MySQLのMEDIUMTEXT型を徹底解説:容量・文字数・性能・運用の実務ガイド
概要:MEDIUMTEXTとは何か
MEDIUMTEXTはMySQL/MariaDBが提供する可変長テキスト型の一つで、最大で16,777,215バイト(約16MB)を格納できます。主に長文記事、ログ、XML/HTML断片、大きなJSON文字列(ただしMySQLのJSON型が有利)など、可変かつ長いテキストデータの保存に用いられます。TEXT型ファミリーにはTINYTEXT、TEXT、MEDIUMTEXT、LONGTEXTがあり、それぞれ格納可能なバイト数が異なります。
容量上限と内部表現
MEDIUMTEXTの最大サイズは16,777,215バイトです。TEXT/BLOB系の各型はデータ長を格納するための長さヘッダを持ち、MEDIUMTEXTは長さを表すヘッダに3バイトを使います(TINYTEXT=1バイト、TEXT=2バイト、MEDIUMTEXT=3バイト、LONGTEXT=4バイト)。
重要な点は「バイト数」であることです。文字数ではなくバイト数で上限が決まるため、使用する文字セット(CHARACTER SET)によって格納できる文字数は変わります。たとえばUTF-8互換のutf8mb4では1文字あたり最大4バイトを使うため、理論上の最大文字数はfloor(16,777,215 / 4) = 4,194,303文字となります。一方、latin1(1バイト文字)なら16,777,215文字を保存できます。
文字数・バイト数を確認する関数
- LENGTH(col):バイト数を返します(マルチバイト文字を考慮した長さ)。
- CHAR_LENGTH(col) または CHARACTER_LENGTH(col):文字数(コードポイント数)を返します。
- OCTET_LENGTH(col):LENGTHと同義でバイト長を返す関数。
ストレージ実装(InnoDBとMyISAMの違い)
内部実装はストレージエンジンによって挙動が異なります。古くはMyISAMがTEXT/BLOBを行本体とは別領域に格納し、行内にはポインタだけを置く方式を採用していました。InnoDBではページサイズ(デフォルト16KB)と行フォーマットによって挙動が変わります。
InnoDB(特にDYNAMICまたはCOMPRESSED行フォーマット)では、長い可変長列はほとんどがオフページ(overflow pages)に格納され、行には20バイト程度のオフセットが置かれます。これにより行サイズ制限を超えないようにできる一方、オフページ参照が増えるとIOが発生しやすくなります。古いCOMPACT/REDUNDANTフォーマットや小さなページサイズを使っている場合は挙動が変わるため注意が必要です。
インデックスと検索の注意点
TEXT/BLOB型はそのままでは全文インデックス(FULLTEXT)を利用できますが、通常のB-Treeインデックスを作る場合は「プレフィックス長」を指定する必要があります。例:CREATE INDEX idx_col ON table(col(1000)); ここで指定する数値はバイト数ベースで考慮してください(utf8mb4なら1000バイト≒250文字程度)。
InnoDBのインデックス長制限はMySQLのバージョンや設定により変わります。一般的にはInnoDBのインデックスキー長は3072バイト(MySQL 5.7/8.0以降のデフォルト設定/Barracudaでの例)を上限にすることが多いですが、古い環境や設定によっては767バイトなど小さい値になることがあるため、実際の値は環境で確認してください。
全文検索を行う場合はInnoDBでもFULLTEXTインデックスが利用できます(MySQL 5.6以降)。ただし、全文検索は単語分割(トークナイゼーション)、ストップワード、最小/最大語長設定、言語対応など設定に依存します。
パフォーマンスと運用上の注意
- 大きなMEDIUMTEXT列を頻繁にSELECTする場合、ネットワーク転送量が増え、クライアント側やサーバ側のメモリ負荷が上がります。必要な場合はSUBSTRINGで部分取得するとか、別テーブルに分割する(大きなカラム専用テーブル)などの設計を検討します。
- UPDATEで大きな列を頻繁に書き換えると、InnoDBのログやIOが増えるためパフォーマンスに影響します。頻繁に更新されるデータは別カラム/別テーブルにする方が良いです。
- バックアップ・レプリケーション時に大きな行が多数あると転送データ量が増えるため、遅延や帯域問題が発生しやすくなります。
- SELECT * で大きなMEDIUMTEXT列を無差別に取得するのは避ける。必要な列のみ指定するか、プレーンテキストのプレビュー(先頭n文字)だけを返すAPIを用意する。
セキュリティとエンコーディングの注意
大きなテキストをウェブに表示する場合はXSSやHTML注入に注意して、適切にエスケープあるいはサニタイズしてください。文字エンコーディングをテーブル・接続・アプリケーションで統一しないと文字化けや予期しないバイト数超過の原因になります。MySQL接続時の文字セット(SET NAMES またはクライアントライブラリの設定)を確認しましょう。
実務的な使い分けと代替案
- 短いテキスト(数百バイト〜数KB)であればVARCHARやTEXTを使う(TEXTは65,535バイトまで)。
- 保存対象が構造化されたJSONなら、MySQLのJSON型を使うことで内部的に最適化・バイナリ化され、仮想カラムやインデックスを組み合わせて効率化できます(MySQL 5.7以降)。
- 非常に大きくて頻繁に配信するコンテンツ(動画や巨大ドキュメント等)は、DBではなくオブジェクトストレージ(S3等)に置き、DBには参照URLを保存する方がスケーラブルです。
- 全文検索が重要ならば、MySQLのFULLTEXTを使うか、ElasticsearchやOpenSearchなどの専用検索エンジンを導入することを検討してください。
ALTER TABLEでの変更例と注意点
既存カラムをTEXTからMEDIUMTEXTに拡張するには次のようなコマンドを使います。ALTER TABLEはテーブルサイズやエンジンによっては時間がかかるためメンテナンスウィンドウやオンラインDDL機能の利用を検討します。
例:ALTER TABLE articles MODIFY COLUMN body MEDIUMTEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
MySQLのバージョンやストレージエンジンによってはALTER TABLEがテーブル再作成を伴いダウンタイムやディスク要件が発生することがあります。Percona Toolkitのpt-online-schema-changeやMySQL 5.6以降のオンラインDDL機能を活用する手もありますが、万能ではないため本番前に検証してください。
実践的なSQL例
テーブル作成例:
CREATE TABLE posts (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255),
body MEDIUMTEXT,
created_at DATETIME
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
部分取得(プレビュー):
SELECT id, title, SUBSTRING(body,1,1000) AS preview FROM posts;
プレフィックスインデックス(例):
CREATE INDEX idx_body_prefix ON posts (body(1000));
全文検索インデックス(InnoDBでの例):
CREATE FULLTEXT INDEX ft_body ON posts (body);
よくある誤解とFAQ
- 「MEDIUMTEXTは文字数16,777,215を格納できる」→ 誤り。上限はバイト数であり、文字数は文字セットによって変わる。
- 「TEXT型は常に行外に格納される」→ ストレージエンジンと行フォーマットに依存します。InnoDBのDYNAMIC/COMPRESSEDでは多くがオフページになりますが、短い場合は行内に収まることもあります。
- 「全文検索はそのまま高速」→ データ量や言語設定、stopword設定、最小単語長などで結果や性能が変わります。専用の検索エンジンの方が高機能でスケーラブルな場合が多いです。
まとめ:選択基準と実務上のアドバイス
MEDIUMTEXTは「数十KB〜数MBの長文を格納したい」ケースで有力な選択肢です。ただし、文字セット(utf8mb4等)によるバイト消費、インデックス制限、ストレージエンジンのオフページ格納、読み書きのIO負荷、バックアップ・レプリケーションへの影響などを総合的に評価する必要があります。可能ならば:
- 短いテキストはVARCHAR/TEXTにする。
- 構造化JSONはJSON型や正規化テーブルを使う。
- 非常に大きなバイナリや配信主体のデータはオブジェクトストレージに置く。
運用面では、接続の文字セットを統一し、長大カラムの頻繁な読み書きを避け、必要に応じてプレフィックス取得や別テーブル分割を検討してください。
参考文献
- MySQL 8.0 Reference Manual — BLOB and TEXT Types
- MySQL 8.0 Reference Manual — Storage Requirements for Data Types
- MySQL 8.0 Reference Manual — InnoDB Physical Storage Structure
- MySQL 8.0 Reference Manual — Full-Text Search
- MySQL 8.0 Reference Manual — The JSON Data Type
- MariaDB Knowledge Base — BLOB and TEXT
投稿者プロフィール
最新の投稿
書籍・コミック2025.12.19内田康夫 — 浅見光彦と信州ミステリが切り開いた「旅する探偵文学」の世界
書籍・コミック2025.12.19京極夏彦 — 妖と謎を編む作家の世界観と読みどころ徹底解説
ファッション2025.12.19ヒストリカルファッションとは何か — 歴史・研究・現代への応用ガイド
ゲーム2025.12.19Mortal Shellを深掘り:暗闇の中で輝く“殻”と戦闘デザインの考察

