| File Format | Row Format | 首部存儲 | 溢出閾值 | 備註 |
| Antelope (舊) | Compact / Redundant | 前 768 字節 | ~768 字節 | MySQL 5.5 默認 |
| Barracuda (新) | Dynamic / Compressed | 僅 20 字節指針 | ~40 字節 | MySQL 5.7+ 默認,真正的溢出頁 |
根因:建表時未顯式指定 ROW_FORMAT
雖然配置了 innodb_file_format = Barracuda,但 InnoDB 為兼容舊版,建表默認仍用 Antelope 格式的 Compact 行格式,除非顯式指定:
-- 官方文檔原文:
-- "tables created with the InnoDB Plugin use the prefix format (Antelope/Compact),
-- unless ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED is specified"
因此表實際使用 ROW_FORMAT=COMPACT,TEXT 列前 768 字節存放在頁內,超過 8126 字節(所有列頁內部分之和)即報錯。
解決方案
方案一:建表時顯式指定 Dynamic(推薦,源頭治理)
CREATE TABLE `t` (
`id` INT PRIMARY KEY,
`content` TEXT
) ENGINE=InnoDB
ROW_FORMAT=DYNAMIC -- 關鍵!
DEFAULT CHARSET=utf8mb4;
DYNAMIC:Barracuda 格式,大字段完全溢出頁,頁內僅存 20 字節指針,行大小極小,幾乎不受 8126 限制。
COMPRESSED:在 Dynamic 基礎上啟用頁壓縮(zlib),存儲更省,CPU 稍增。
方案二:現有表在線變更 ROW_FORMAT(MySQL 5.6+)
ALTER TABLE `t` ROW_FORMAT=DYNAMIC;
-- 或
ALTER TABLE `t` ROW_FORMAT=DYNAMIC, ALGORITHM=INPLACE, LOCK=NONE; -- 5.6+ 在線 DDL,不鎖表
執行後需 重新插入/更新數據 才會按新格式存儲(舊行不會自動重組)。
方案三:全局默認調整(MySQL 5.7+)
[mysqld]
innodb_file_format = Barracuda
innodb_file_per_table = ON
innodb_default_row_format = DYNAMIC -- 5.7 新增,新建表默認 Dynamic
8.0 已移除 innodb_file_format,默認即為 Barracuda + Dynamic。
驗證表行格式
SHOW TABLE STATUS LIKE 't'\G
-- 關注 Row_format 列:Dynamic / Compact / Compressed
-- 或查詢信息模式
SELECT NAME, ROW_FORMAT FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME LIKE 'db/t';
避坑指南
- 多 TEXT 列表:單表超過 10 個
TEXT/BLOB 列,即使 Dynamic 也可能因指針累積超限。拆分為多表或合併為 JSON。
- 報錯誤導性:
Change some columns to TEXT or BLOBs 提示誤導(字段已是 TEXT),5.1.61+ 優化為 Row size too large (> 8126). Consider changing some columns to TEXT or BLOB or using ROW_FORMAT=DYNAMIC/COMPRESSED。
innodb_strict_mode=ON(默認開啟)會在建表/插入時嚴格檢查行大小,關閉可暫時繞過但極不推薦,會導致數據寫入失敗或損壞。
總結
Row size too large 核心原因是表行格式為 Compact(Antelope),導致大字段前綴存頁內。徹底解決:建表/ALTER 指定 ROW_FORMAT=DYNAMIC,配合 innodb_default_row_format=DYNAMIC 全局生效。升級至 MySQL 8.0 可一勞永逸獲得現代默認值。
- 上一篇文章: 內網 SSH/MySQL 登錄緩慢根因與秒級優化:關閉 DNS 反向解析
- 下一篇文章: Windows/Linux 下命令行登錄 MySQL 完整操作指南
Copyright ©
程式碼之家 All Rights Reserved