本文為前文 (ID 171750) 的補充,針對錯誤觸發條件、VARCHAR 版本差異、TINYTEXT 適用邊界、InnoDB 行格式影響進行更深入說明,幫助開發者精準判斷何時需變更欄位類型。
CREATE TABLE、ALTER TABLE ... ADD COLUMN、ALTER TABLE ... MODIFY COLUMN 時,MySQL 會計算**所有非 BLOB/TEXT 欄位的最大可能儲存長度總和** (含長度前綴 1-2 bytes)。Row size too large,**即使實際資料極短也會被攔截**,因為是靜態定義檢查。TEXT/BLOB 欄位行內固定佔 20 bytes (指標),**不計入 65535 計算**,故改為 TEXT 類型可繞過檢查。| 版本 | 長度前綴 | 最大字元數 | 備註 |
|---|---|---|---|
| 5.0.3 前 | 1 byte | 255 字元 | 長度 0-255 |
| 5.0.3+ | 1-2 bytes | 65535 字元 | 長度 0-65535;>255 字元時前綴 2 bytes |
| 業務最大長度 | 建議類型 | 理由 |
|---|---|---|
| ≤ 255 字元、高頻讀寫 | VARCHAR(N) | 支援 DEFAULT、索引、就地更新 |
| ≤ 255 字元、低頻、需省行預算 | TINYTEXT | 行內最小開銷 |
| 256 - 65535 字元 | TEXT | 自動溢頁,行內固定 20 bytes |
| > 64KB | LONGTEXT / 拆表 | 超出 TEXT 上限 |
ROW_FORMAT=COMPACT/REDUNDANT (5.7 預設 COMPACT):**受 65535 限制**,大欄位若超過頁面 1/2 會溢頁,但定義長度仍計入行預算。ROW_FORMAT=DYNAMIC/COMPRESSED (需 innodb_file_per_table=ON + innodb_large_prefix=ON,5.7.7+ 預設開啟):大幅放寬,支援單行超過 64KB (實際上限約 16MB),**大欄位完全溢頁不計入行內預算**。SHOW TABLE STATUS LIKE 'tbl'\G 看 Row_format。VARCHAR 但未超過溢頁門檻 (40 bytes),可強制改為 TEXT 觸發溢頁。SELECT
TABLE_NAME,
SUM(
CASE DATA_TYPE
WHEN 'varchar' THEN CHARACTER_MAXIMUM_LENGTH *
CASE CHARACTER_SET_NAME WHEN 'utf8mb4' THEN 4 WHEN 'utf8' THEN 3 ELSE 1 END + 2
WHEN 'char' THEN CHARACTER_MAXIMUM_LENGTH *
CASE CHARACTER_SET_NAME WHEN 'utf8mb4' THEN 4 WHEN 'utf8' THEN 3 ELSE 1 END
WHEN 'varbinary' THEN CHARACTER_MAXIMUM_LENGTH + 2
WHEN 'binary' THEN CHARACTER_MAXIMUM_LENGTH
ELSE 0 END
) AS est_row_bytes
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'your_db'
AND DATA_TYPE NOT IN ('text','blob','longtext','mediumtext','tinytext')
GROUP BY TABLE_NAME
HAVING est_row_bytes > 60000
ORDER BY est_row_bytes DESC;
結果中 est_row_bytes 越接近 65535 越危險,優先處理。
理解儲存引擎行格式與欄位類型的交互關係,才能在 schema 設計階段就規避此類硬性限制。