測試結論速覽
| 版本 | 行格式 | 字段數 >10 | 單字段 >768B | 結果 |
| 5.1 | Compact (默認) | 是 | 否 (<768B) | 成功 |
| 5.1 | Compact | 是 | 是 (>768B) | 失敗:Got error 139 |
| 5.5 | Compact (默認) | 是 | 是 (>768B) | 失敗:Row size too large (>8126) |
| 5.5 | Dynamic/Compressed | 是 | 是 (>768B) | 成功 |
核心機制解析
Compact / Redundant(Antelope 文件格式)
- 每行**固定在頁內存儲 768 字節前綴**(BLOB/TEXT/VARCHAR),溢出頁存餘下數據。
- InnoDB 頁大小 16 KB,扣除頁頭尾、事務頭、**單行實際可用 ≈ 8126 字節**。
- 10 個 BLOB × 768 B = 7680 B,接近上限 → 第 11 個大字段直接導致「Row size too large」。
Dynamic / Compressed(Barracuda 文件格式,5.5+)
- **完全溢出頁存儲**,行內僅存 20 字節指針。
- 單行可容納數百個大字段,無 768B 限制。
- 需滿足:
innodb_file_per_table=ON + innodb_file_format=Barracuda + ROW_FORMAT=DYNAMIC。
啟用 Barracuda + Dynamic 完整步驟(MySQL 5.5/5.6/5.7)
1. 配置文件 my.cnf 生效
[mysqld]
innodb_file_per_table = 1
innodb_file_format = Barracuda
innodb_file_format_max = Barracuda # 5.7+ 建議加上
innodb_large_prefix = 1 # 允許 3072 字節索引前綴,間接支援大字段
2. 動態生效(重啟失效,適合臨時測試)
SET GLOBAL innodb_file_format = Barracuda;
SET GLOBAL innodb_file_per_table = 1;
SET GLOBAL innodb_large_prefix = 1;
3. 建表指定行格式
CREATE TABLE t_blob_test (
id INT AUTO_INCREMENT PRIMARY KEY,
b1 LONGBLOB, b2 LONGBLOB, b3 LONGBLOB, b4 LONGBLOB, b5 LONGBLOB,
b6 LONGBLOB, b7 LONGBLOB, b8 LONGBLOB, b9 LONGBLOB, b10 LONGBLOB,
b11 LONGBLOB, b12 LONGBLOB
) ENGINE=InnoDB ROW_FORMAT=DYNAMIC DEFAULT CHARSET=utf8mb4;
4. 驗證行格式
SHOW TABLE STATUS LIKE 't_blob_test'\G
-- Row_format: Dynamic → 成功
-- Row_format: Compact → 未生效,檢查上述參數
避坑指南
- 參數修改僅影響後續建表:舊表需
ALTER TABLE t ROW_FORMAT=DYNAMIC; 重建(會鎖表,大表用 pt-online-schema-change)。
- MySQL 8.0 預設即為 Barracuda + Dynamic:
innodb_file_format 參數已移除,無需配置。
- 索引長度限制:即使行格式 Dynamic,單列索引仍受 767/3072 字節限制(
innodb_large_prefix 控制),BLOB/TEXT 不能直接建索引,需指定前綴長度 INDEX idx_b1 (b1(255))。
- 備份恢復:
mysqldump 導出的 CREATE TABLE 不含 ROW_FORMAT,恢復時會按當前實例預設格式建表,需手動補充或導入後 ALTER。
最佳實踐建議
- 大對象首選外部存儲:圖片、文檔存 S3/MinIO/OSS,DB 僅存 URL + 元數據,徹底規避行大小限制。
- 必須存 DB 時:MySQL 5.7+ / 8.0 +
ROW_FORMAT=DYNAMIC + LONGBLOB/LONGTEXT,單表字段數建議 ≤ 20。
- 監控指標:
Innodb_row_lock_waits、Innodb_buffer_pool_pages_dirty、大表 DATA_LENGTH 增長趨勢。