文檔常稱 VARCHAR(65535) 為上限,但實際可用長度受行大小限制 (65535 bytes)、字符集編碼、NULL 標誌位、長度前綴字節 (1-2 bytes) 多重約束。本文通過數學推導、實測驗證、對比 CHAR/TEXT,給出精確計算公式與選型指南。
MAX_VARCHAR_LENGTH = FLOOR( (65535 - NULL_BYTES - LENGTH_PREFIX - SUM_OTHER_COLS) / MAX_BYTES_PER_CHAR )
NULL_BYTES = 1 (若列允許 NULL,NULL 位圖佔 1 bit,向上取整到 byte;單獨一列通常 1 byte)
LENGTH_PREFIX = 1 (若 MAX ≤ 255) 或 2 (若 MAX > 255)
SUM_OTHER_COLS = 同表其他列定義長度總和 (按最大字節數計算)
MAX_BYTES_PER_CHAR = 字符集最大字節數 (latin1=1, gbk=2, utf8=3, utf8mb4=4)
-- 允許 NULL:最大 65532
CREATE TABLE t_null (c VARCHAR(65532)) ENGINE=InnoDB CHARSET=latin1; -- OK
CREATE TABLE t_null (c VARCHAR(65533)) ENGINE=InnoDB CHARSET=latin1; -- ERROR 1118 Row size too large
-- NOT NULL:最大 65533
CREATE TABLE t_nn (c VARCHAR(65533) NOT NULL) ENGINE=InnoDB CHARSET=latin1; -- OK
CREATE TABLE t_nn (c VARCHAR(65534) NOT NULL) ENGINE=InnoDB CHARSET=latin1; -- ERROR 1118
差異原因: NULL 列需額外 1 byte NULL 標誌位;NOT NULL 省下此位,可多存 1 字元。
CREATE TABLE t4 (
c INT, -- 4 bytes
c2 CHAR(30), -- 30 * 3 = 90 bytes (utf8)
c3 VARCHAR(N) -- utf8
) CHARSET=utf8;
-- N_max = (65535 - 1 - 2 - 4 - 90) / 3 = 21812
-- 1: NULL 位圖; 2: VARCHAR 長度前綴; 4: INT; 90: CHAR(30) utf8
| 特性 | CHAR(M) | VARCHAR(M) | TEXT / BLOB |
|---|---|---|---|
| 長度範圍 | 0-255 | 0-65535 (受行限制) | TINY: 255, TEXT: 64KB, MEDIUM: 16MB, LONG: 4GB | 儲存方式 | 固定長度,右側空格填充 | 變長,實際長度+1/2 byte 前綴 | 溢出頁存儲,指標在行內 |
| 尾部空格 | 讀取時截斷 | 保留 | 保留 |
| 索引效能 | 極高 (固定寬度) | 高 | 需指定前綴長度 (如 idx(col(100))) |
| 預設值 | 支援 | 支援 | 不支援 |
| InnoDB 建議 | 短固定碼 (如 ISO 代碼) | 首選 (變長、節省空間、無碎片) | 大文本、JSON、日志 |
CHAR (如 MD5、UUID 去連字號、國家代碼、性別、狀態碼)。VARCHAR(合理上限),不要盲目設 255/65535,根據業務上限 + 20% 冗餘設定 (如手機號 11 → VARCHAR(15),郵箱 254 → VARCHAR(191) 兼容索引前綴限制)。TEXT / LONGTEXT / JSON (MySQL 5.7+)。BLOB / LONGBLOB。核心結論: VARCHAR 理論上限 65535,實際受行大小、字符集、NULL 屬性多重制約,單列極限通常在 16K-65K 區間。合理設定長度而非追求最大值,兼顧索引效能、儲存效率與遷移相容性。