錯誤現場
The table is full
-- 實際數據文件大小:4,294,963,640 字節 (接近 4GB = 4,294,967,296 字節)
根因:MyISAM 內部指針預設 4 字節 (32 位),最大寻址 4GB
myisamchk -dv tbl_name 顯示 Max datafile length: 4294967296 (4GB)
- InnoDB 不受此限制 (64 位表空間 ID + 頁號)
解決方案:ALTER TABLE 重設預估參數
ALTER TABLE `cdb_posts`
MAX_ROWS = 1000000000,
AVG_ROW_LENGTH = 15000;
參數含義與計算邏輯
| 參數 | 作用 | 設定建議 |
MAX_ROWS | 預估最大行數,決定指針字節數 | 設為業務上限 × 10 (如 1 億 → 10 億),讓 MySQL 選用 6/8 字節指針 |
AVG_ROW_LENGTH | 預估平均行長度,配合 MAX_ROWS 計算總大小 | 用 SHOW TABLE STATUS 實際 Avg_row_length × 1.5~2 倍 |
執行效果驗證
# 修改前
Max datafile length: 4294967296 (4GB)
Datafile pointer: 4 bytes
# 修改後 (執行約 30 分鐘,雙 Athlon 專業服務器)
Max datafile length: 281474976710654 (256 TB)
Max keyfile length: 4398046510079 (4 TB)
Datafile pointer: 6 bytes -- 關鍵:從 4 字節升級為 6 字節
原理圖解:日記本比喻
「假設日記本 10 頁,目錄 1 字節 (0-9) 足夠。塞進 2 頁變 12 頁,1 字節目錄找不到後 2 頁 → 報錯。
ALTER TABLE ... MAX_ROWS=1000000000 AVG_ROW_LENGTH=15000 相當於告訴 MySQL:這本子有 10 億頁,每頁 1.5 萬字節。MySQL 於是拿出 6 字節 (甚至 8 字節) 做目錄,能寻址 256 TB,問題解決。」
代價與副作用
- 索引文件 (
.MYI) 指針同步變大 (4→6 字節),索引體積微增 (~1-2%)
- 執行期間**全表鎖定**,大表耗時長 (本例 30 分鐘),建議低峰期或主從切換後在從庫執行
- MySQL 5.6+
ALGORITHM=INPLACE 不支援此操作,必須 ALGORITHM=COPY (重建表)
根治建議:遷移至 InnoDB
ALTER TABLE `cdb_posts` ENGINE = InnoDB;
- InnoDB 表空間 64 位,單表理論上限 64 TB (受限於表空間文件數)
- 獲得事務、行級鎖、崩潰恢復、外鍵、自適應哈希索引等現代特性
- MySQL 5.7+ 預設即 InnoDB,MyISAM 僅存留兼容
適用場景總結
| 場景 | 推薦方案 |
| 歷史 MyISAM 大表、暫時無法遷移 | ALTER TABLE ... MAX_ROWS=... AVG_ROW_LENGTH=... 緊急突破 |
| 新建大表、預估超 4GB | 直接建 InnoDB,或建表時指定 MAX_ROWS/AVG_ROW_LENGTH |
| 長期演進 | 全面遷移 InnoDB,配合分區表/分庫分表架構 |