数据库碎片是长期增删改后留下的"数据空洞",会让查询变慢、占用磁盘。定期优化可恢复性能。
一、碎片产生原理
MySQL InnoDB 引擎删除数据后不会立即释放磁盘空间,而是标记为可复用。长期累积形成"碎片",导致数据文件比实际数据大 30%-50%,查询需要扫描更多页,IO 增加。
二、检测碎片命令
2.1 查看所有表碎片率
SELECT
table_name,
ROUND(data_length/1024/1024,2) AS data_mb,
ROUND(index_length/1024/1024,2) AS index_mb,
ROUND(data_free/1024/1024,2) AS free_mb,
ROUND(data_free/(data_length+index_length+1)*100,2) AS frag_pct
FROM information_schema.tables
WHERE table_schema='dede_db'
ORDER BY free_mb DESC;
frag_pct 超过 20% 即需优化。
三、优化命令
3.1 OPTIMIZE TABLE(推荐)
OPTIMIZE TABLE dede_archives;
OPTIMIZE TABLE dede_addonarticle;
OPTIMIZE TABLE dede_arctiny;
OPTIMIZE TABLE dede_taglist;
3.2 ALTER TABLE 重建
ALTER TABLE dede_archives ENGINE=InnoDB;
等价于 OPTIMIZE,但需注意会锁表。
3.3 ANALYZE 更新统计
ANALYZE TABLE dede_archives;
更新索引统计信息,让查询优化器选择更优执行计划。
四、批量优化脚本
#!/bin/bash
# optimize_all_tables.sh
DB_USER="root"
DB_PASS="yourpass"
DB_NAME="dede_db"
TABLES=$(mysql -u$DB_USER -p$DB_PASS -e "SHOW TABLES" $DB_NAME | tail -n +2)
for t in $TABLES; do
echo "优化 $t ..."
mysql -u$DB_USER -p$DB_PASS -e "OPTIMIZE TABLE $t;" $DB_NAME
done
echo "全部完成"
五、织梦主要表的优化顺序
| 表名 | 用途 | 优化优先级 |
|---|---|---|
| dede_archives | 文档主表 | 高 |
| dede_addonarticle | 正文 | 高 |
| dede_arctiny | 索引 | 高 |
| dede_taglist | tag关联 | 中 |
| dede_log | 日志 | 中 |
| dede_search_cache | 搜索缓存 | 低 |
六、常见问题原因分析
6.1 优化期间站点卡顿
原因:OPTIMIZE 会锁表,期间无法读写。
解决:凌晨低峰期执行;或使用 pt-online-schema-change 在线操作。
6.2 优化后磁盘未释放
原因:InnoDB 共享表空间 ibdata1 不会回收空间。
注意:若使用共享表空间,需导出数据 → 删除 ibdata1 → 重新导入才能真正释放空间。
七、配置 innodb_file_per_table
建议开启独立表空间,让每张表使用独立 .ibd 文件,OPTIMIZE 即可释放磁盘:
# my.cnf
[mysqld]
innodb_file_per_table=1
八、定时优化任务
宝塔 → 计划任务 → 每周日凌晨 3 点执行:
0 3 * * 0 /bin/bash /root/optimize_all_tables.sh >> /www/wwwlogs/db_optimize.log
九、行动指引
建议建立数据库健康度监控:每周记录碎片率、表大小、慢查询数。结合宝塔可视化监控面板观察磁盘 IO 趋势,发现异常及时优化。同时关注 MySQL 慢查询日志,将优化重心从"碎片清理"逐步延伸到"索引调优",让数据库性能持续稳定。