MySQL表碎片整理
1. OPTIMIZE TABLE 命令
这是最常用的碎片整理方法:
-- 基本用法
OPTIMIZE TABLE table_name;
-- 整理多个表
OPTIMIZE TABLE table1, table2, table3;
-- 实际示例
OPTIMIZE TABLE users, orders, products;
适用场景:
- MyISAM、InnoDB、ARCHIVE 表
- 表经过大量 DELETE、UPDATE 操作后
- 需要回收空间并优化性能
2. ALTER TABLE 重建
-- 方法1:简单重建
ALTER TABLE table_name ENGINE=InnoDB;
-- 方法2:带字符集重建(保持原字符集)
ALTER TABLE table_name ENGINE=InnoDB CHARACTER SET utf8mb4;
-- 实际示例
ALTER TABLE large_table ENGINE=InnoDB;
3. 针对不同存储引擎的方法
InnoDB 表
-- 使用 OPTIMIZE TABLE(推荐)
OPTIMIZE TABLE innodb_table;
-- 或者使用 ALTER TABLE
ALTER TABLE innodb_table FORCE;
-- 在线 DDL(MySQL 5.6+)
ALTER TABLE innodb_table ALGORITHM=INPLACE, LOCK=NONE;
MyISAM 表
-- OPTIMIZE TABLE
OPTIMIZE TABLE myisam_table;
-- 或者使用 REPAIR TABLE
REPAIR TABLE myisam_table;
-- 带选项的修复
REPAIR TABLE myisam_table QUICK;
4. 批量整理脚本
-- 整理所有表的存储过程
DELIMITER $$
CREATE PROCEDURE optimize_all_tables()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE tbl_name VARCHAR(255);
DECLARE cur CURSOR FOR
SELECT table_name
FROM information_schema.tables
WHERE table_schema = DATABASE()
AND table_type = 'BASE TABLE';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur;
read_loop: LOOP
FETCH cur INTO tbl_name;
IF done THEN
LEAVE read_loop;
END IF;
SET @sql = CONCAT('OPTIMIZE TABLE `', tbl_name, '`');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END LOOP;
CLOSE cur;
END$$
DELIMITER ;
-- 调用存储过程
CALL optimize_all_tables();
5. 命令行工具
# 使用 mysqlcheck 工具
mysqlcheck -o database_name table_name
mysqlcheck -o database_name # 整理整个数据库
# 整理所有数据库
mysqlcheck -o --all-databases
# 带连接参数
mysqlcheck -o -u username -p database_name
6. 自动化脚本(Shell)
#!/bin/bash
# 数据库连接信息
DB_HOST="localhost"
DB_USER="username"
DB_PASS="password"
DB_NAME="database_name"
# 整理单个数据库
mysqlcheck -h $DB_HOST -u $DB_USER -p$DB_PASS -o $DB_NAME
# 或者整理特定表
mysql -h $DB_HOST -u $DB_USER -p$DB_PASS -e "OPTIMIZE TABLE table1, table2;" $DB_NAME
7. 检查碎片程度
在整理前先检查碎片情况:
-- 查看表碎片情况
SELECT
TABLE_NAME,
ENGINE,
TABLE_ROWS,
DATA_LENGTH,
INDEX_LENGTH,
DATA_FREE,
ROUND(DATA_FREE/(DATA_LENGTH+INDEX_LENGTH)*100, 2) AS fragment_percent
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'your_database'
AND DATA_FREE > 0
ORDER BY fragment_percent DESC;
注意事项
- 锁表问题:OPTIMIZE TABLE 会锁表,建议在业务低峰期执行
- 磁盘空间:需要额外的磁盘空间来完成操作
- InnoDB 注意事项:
- OPTIMIZE TABLE 在 InnoDB 中会被映射为 ALTER TABLE
- 使用
innodb_file_per_table可以更好地管理空间
- 备份:重要操作前建议备份数据
- 复制环境:在主从复制环境中,OPTIMIZE TABLE 会被复制到从库
最佳实践
- 定期监控表碎片情况
- 在低峰期执行整理操作
- 对于大表,考虑分批次整理
- 使用
pt-online-schema-change工具进行在线表重构
选择合适的方法取决于你的具体需求、表的大小和业务影响程度。