大量刪除、更新操作會在數據文件中產生不連續的空洞(碎片),影響查詢性能與磁盤利用率。不同存儲引擎的碎片整理方式截然不同。
SHOW TABLE STATUS LIKE 'table_name'\G
-- 關鍵指標:Data_free > 0 表示存在碎片
-- 方法 1:OPTIMIZE TABLE(推薦)
OPTIMIZE TABLE table_name;
-- 方法 2:mysqlcheck 命令行工具
mysqlcheck -u root -p --optimize database_name table_name
-- 方法 3:重建表(等效)
ALTER TABLE table_name ENGINE=MyISAM;
-- 優化前
Data_free: 40
Avg_row_length: 45
-- 優化後
Data_free: 0
Avg_row_length: 32
Data_length: 96
OPTIMIZE TABLE 和 mysqlcheck -o 對 InnoDB **無效**(實際執行 ANALYZE TABLE,僅更新統計信息)。
| 方法 | 適用場景 | 操作 | 風險 |
|---|---|---|---|
| ALTER TABLE ... ENGINE=InnoDB | 小表/中表 | 重建表空間,回收碎片 | 鎖表,阻塞寫入 |
| pt-online-schema-change | 大表/生產環境 | 無鎖在線重建 | 需安裝 Percona Toolkit |
| 新建表 + 數據遷移 + 重命名 | 超大表 | 手動控制流程 | 操作複雜,需應用配合 |
-- 使用 Percona Toolkit(推薦)
pt-online-schema-change \
--alter "ENGINE=InnoDB" \
D=db_name,t=table_name \
--execute
-- 或手動分步驟
CREATE TABLE new_table LIKE old_table;
ALTER TABLE new_table ENGINE=InnoDB; -- 可調整參數
INSERT INTO new_table SELECT * FROM old_table;
RENAME TABLE old_table TO old_table_bak, new_table TO old_table;
DROP TABLE old_table_bak;
-- 查看表空間碎片率
SELECT
TABLE_NAME,
DATA_FREE,
DATA_LENGTH,
ROUND(DATA_FREE / DATA_LENGTH * 100, 2) AS fragment_ratio
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'db_name'
AND DATA_FREE > 0
ORDER BY fragment_ratio DESC;
TRUNCATE 或分批刪除ANALYZE TABLE 更新統計信息Data_free 指標,設定告警閾值工具推薦:
innodb_ruby、mysqlfragfinder(Python) 可深度分析 InnoDB 頁面碎片分佈。