高頻 DML(INSERT/UPDATE/DELETE)配合大量二級索引,極易導致 InnoDB 表空間碎片化,表現為 .ibd 文件遠大於實際數據量。本文記錄一次生產環境 transfe 表(354 萬行、6 個索引)的碎片整理全過程,文件從 5.6G 降至 2.9G,釋放 48% 空間。
-- 表基本信息 mysql> show table status from emoprod like 'transfe'\G Name: transfe Engine: InnoDB Rows: 3,543,033 Avg_row_length: 260 Data_length: 924,401,664 (~881 MB) Index_length: 2,128,576,512 (~2.0 GB) -- 索引比數據大 2.3 倍! Data_free: 7,340,032 (~7 MB 可回收碎片) Auto_increment: NULL Create_time: 2016-09-25 17:43:44 -- 文件系統層面 [root@emo-mysql-02 emoprod]# ls -lh transfe.ibd -rw-r----- 1 mysql mysql 5.6G Sep 28 16:03 transfe.ibd -- 實際佔用 5.6 GB
核心現象:索引長度(2.1G)遠超數據長度(0.9G),.ibd 文件(5.6G)遠超 Data+Index(2.9G),說明存在大量頁碎片與未釋放空間。
mysql> optimize table transfe; +------------------------+----------+----------+-------------------------------------------------------------------+ | Table | Op | Msg_type | Msg_text | +------------------------+----------+----------+-------------------------------------------------------------------+ | emoprod.transfe | optimize | note | Table does not support optimize, doing recreate + analyze instead | | emoprod.transfe | optimize | status | OK | +------------------------+----------+----------+-------------------------------------------------------------------+ 2 rows in set (5 min 15.06 sec)
關鍵提示:InnoDB 不支援原生 OPTIMIZE,實際執行 重建表(recreate)+ 分析統計信息,相當於 ALTER TABLE ... ENGINE=InnoDB。
-- 進程狀態 mysql> show processlist; Id: 1180 | User: root | State: altering table | Info: optimize table transfe -- 事務信息 mysql> select * from information_schema.INNODB_TRX\G trx_id: 1918481819 trx_state: RUNNING trx_query: optimize table transfe trx_tables_locked: 1 -- 持有表鎖,會阻塞寫入!
| 指標 | 整理前 | 整理後 | 變化 |
|---|---|---|---|
| .ibd 文件大小 | 5.6 GB | 2.9 GB | -48% |
| Data_length | 881 MB | 1,066 MB | +21%(數據頁緊湊) |
| Index_length | 2,128 MB | 2,961 MB | +39%(索引頁重組) |
| Avg_row_length | 260 B | 200 B | -23%(行存儲更緊湊) |
| Rows | 3,543,033 | 5,312,336 | 統計信息更新更準確 |
| Data_free | 7 MB | 6 MB | 碎片基本清理 |
ALGORITHM=INPLACE 的 OPTIMIZE(部分場景無鎖),但重建表仍需拷貝數據,耗時與表大小成正比。ALTER TABLE transfe ENGINE=InnoDB(同等效果)pt-online-schema-change(在線無鎖重建,推薦大表)INSTANT DDL(部分操作秒級完成)ANALYZE TABLE,優化器統計更準確,查詢計劃可能變更,需觀察慢查詢。SHOW INDEX 檢查 Cardinality,刪除低選擇性索引TRUNCATE 或分批 DELETE ... LIMIT 1000 + OPTIMIZEinnodb_file_per_table=ON 獨立表空間「碎片整理是治標,合理的表結構與索引設計才是治本。
每次OPTIMIZE都是對資源的昂貴消耗,請像對待手術一樣謹慎規劃。」
本文操作環境:MySQL 5.6 (Percona Server),InnoDB 獨立表空間,生產從庫執行,主庫同步延遲 < 10s。完整日誌已歸檔備查。