MySQL 4.1+:VARCHAR(N) 中 N = 最大字符數 (字母、漢字、Emoji 均計 1)。
4.1 前:N = 最大字節數。
單行上限 65,535 字節 (除去行頭信息)。扣除項:
(NULL列數 + 7) / 8 字節| 列定義 | NULL標識 | 長度標識 | 可用字節 | 最大字符數 (latin1/gbk/utf8mb4) |
|---|---|---|---|---|
| VARCHAR(N) NOT NULL | 0 | 1 (N<256) / 2 (N≥256) | 65535 - 1/2 | 65533 / 32766 / 16383 |
| VARCHAR(N) DEFAULT NULL | 1 bit → 1 字節 | 1/2 | 65535 - 2/3 | 65532 / 32765 / 16382 |
固定部分: 0
變長標識: 10列 × 1字節 = 10 (均 < 256)
NULL位圖: (10+7)/8 = 2 字節
已用: 100×9 + 10 + 2 = 912
剩餘: 65535 - 912 = 64623
第10列長度標識: 2 (因 N > 256)
最大 N = 64623 - 2 = 64621 字節 = 64621 字符 (latin1)
innodb_file_format=Barracuda)Compressed 額外啟用 zlib 壓縮,CPU 換空間[mysqld]
innodb_file_format=Barracuda
innodb_file_per_table=ON
innodb_default_row_format=DYNAMIC
ROW_FORMAT=FIXED:VARCHAR 按定長存儲 (按最大長度填充空格),極度浪費空間,但讀取最快ROW_FORMAT=DYNAMIC:標準變長存儲,長度前綴 + 數據myisampack:生成只讀壓縮表 (ROW_FORMAT=COMPRESSED)| 場景 | 陷阱 | 正解 |
|---|---|---|
| VARCHAR(255) utf8mb4 | 以為 255 字符,實際最大 255×4=1020 字節 → 需 2 字節長度前綴 | 明確知曉:長度前綴由「定義最大字節數」決定,非實際存儲 |
| 建表報錯 Row size too large | 多 VARCHAR(255) utf8mb4 導致定義行長超過 65535 | 改用 TEXT/JSON、拆表、或升級 Barracuda + DYNAMIC |
| 索引長度限制 767 字節 | utf8mb4 下 VARCHAR(191) 才能建索引 (191×4=764) | MySQL 5.7+ 開啟 innodb_large_prefix=ON (默認) 支持 3072 字節 → VARCHAR(768) 可建索引 |
| CHAR vs VARCHAR | CHAR(100) utf8mb4 固定佔 400 字節 | 定長極短、高頻更新列用 CHAR (避免碎片),其餘用 VARCHAR |
Innodb_buffer_pool_pages_data、Innodb_row_lock_waits、表空間增長率。VARCHAR 看似簡單,實則涉及字符集編碼、行格式、溢出機制、索引長度限制多層機制。掌握「N 是字符數、存儲按字節、前綴看定義長度、InnoDB 看文件格式」這條主線,即可在建表、加索引、排查 Row size too large、優化大字段存儲時遊刃有餘。