| 欄位定義 | 位元組數 (含長度前綴) | 可否建立單欄索引 |
| VARCHAR(255) | 255×4 + 2 = 1022 | ❌ 超過 767 |
| VARCHAR(191) | 191×4 + 2 = 766 | ✅ 最大安全長度 |
| VARCHAR(255) CHARSET=utf8 | 255×3 + 2 = 767 | ✅ 緊貼上限 |
實測錯誤訊息
CREATE TABLE t (id BIGINT PRIMARY KEY, a VARCHAR(255)) CHARSET=utf8mb4;
ALTER TABLE t ADD INDEX idx_a (a);
-- ERROR 1071 (42000): Specified key was too long; max key length is 767 bytes
聯合索引實測
CREATE TABLE t2 (
id BIGINT PRIMARY KEY,
a TEXT, b TEXT, c TEXT, d TEXT, e TEXT
) CHARSET=utf8mb4;
-- 255*4 = 1020 bytes per column prefix
-- 4 columns * 1020 = 4080 > 3072 會失敗
ALTER TABLE t2 ADD INDEX idx_abcd (a(255), b(255), c(255), d(255));
-- ERROR 1071: max key length is 3072 bytes
-- 正確:4 個 255 前綴 = 4*765 = 3060 < 3072
ALTER TABLE t2 ADD INDEX idx_abcd (a(255), b(255), c(255), d(255));
-- 成功(每欄前綴 255 字元 = 765 位元組)
注意:a(255) 表示**字元數**前綴,UTF8MB4 實際佔 765 位元組。
應對策略
- 縮短欄位長度: 業務允許時用
VARCHAR(191) 替代 255。
- 使用前綴索引:
INDEX idx_name (long_col(50)),覆蓋率評估 SELECT COUNT(DISTINCT LEFT(col,50))/COUNT(*) FROM t。
- 升級 MySQL 5.7.7+ / 8.0: 啟用
innodb_large_prefix=ON(預設開啟),單欄索引上限放寬至 **3072 位元組**,VARCHAR(255) 可直接建立索引。
- 改用哈希索引/全文索引: 長字串精確查詢可存
CRC32/MD5 值建立索引,或 FULLTEXT。
- 避免過長聯合索引: 單表索引總長度逼近 3072 時,拆分為多個索引或調整查詢模式。
版本對照