2025年09月09日/ 浏览 7
在日常的MySQL数据库维护中,我们常常会忽视一个隐形杀手——索引碎片。随着数据不断插入、更新和删除,索引页会逐渐变得零散,导致查询性能下降。我曾经维护过一个电商系统,就因为长期未处理索引碎片,简单查询从200ms飙升到2秒,通过碎片整理后性能立即恢复了80%。
sql
SHOW TABLE STATUS LIKE '表名'\G
重点关注Data_free
字段,它表示未使用的碎片空间(单位字节)。当这个值超过数据大小的10%时就需要警惕。例如某用户表显示Data_free: 104857600
(100MB),而表总大小才1GB,说明碎片率已达10%。
sql
SELECT
table_name,
engine,
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))*100,2) as frag_ratio
FROM
information_schema.tables
WHERE
table_schema = '你的数据库名'
AND data_free > 0
ORDER BY frag_ratio DESC;
这个查询会给出碎片率排名,建议重点关注frag_ratio大于15%的表。
Percona Toolkit中的pt-index-usage工具可以生成可视化报告:
bash
pt-index-usage -u用户名 -p密码 --host=主机名 慢查询日志文件
典型场景案例:
– 频繁UPDATE导致行迁移(Row Migration)
– 大量DELETE后未重用空间
– 随机插入导致B+树分裂
性能影响三宗罪:
1. 增加I/O操作:需要读取更多物理页
2. 缓存效率降低:相同内存缓存的数据变少
3. 查询计划失真:优化器可能选择非最优路径
sql
ALTER TABLE 表名 ENGINE=InnoDB;
注意:此操作会获取MDL锁,大表建议在低峰期进行。某金融系统在凌晨2点执行该操作,使200GB表的查询速度提升40%。
bash
pt-online-schema-change --alter="ENGINE=InnoDB" D=数据库名,t=表名 --execute
这个工具通过创建影子表的方式实现零停机维护,特别适合7×24系统。
对于TB级表,可采用分区表维护:
sql
ALTER TABLE 大表 REBUILD PARTITION p0,p1;
填充因子控制:创建表时指定key_block_size
sql
CREATE TABLE ... KEY_BLOCK_SIZE=8;
定期维护计划:每月执行一次碎片检查
handler_read_rnd_next
增长情况索引碎片就像数据库的”血管栓塞”,需要定期检查清理。建议将碎片检查纳入DBA的常规巡检清单,结合慢查询日志分析,才能保持数据库长期高效运行。记住,预防永远比治疗更经济——良好的表设计可以减少80%的碎片问题。