针对 MySQL 千万级大表的数据清理,需兼顾性能、业务连续性、存储空间回收和数据一致性。以下是分步骤的解决方案:
一、清理前的准备工作
明确清理规则
与业务方确认数据保留策略(如保留近6个月数据),避免误删有效数据。备份数据
使用mysqldump
或物理备份工具(如Percona XtraBackup)对目标表做全量备份:bashmysqldump -h host -u user -p database table > backup.sql
低峰期操作
选择业务流量最低的时间段(如凌晨)执行清理,减少对线上服务的影响。
二、高效数据清理方案
方案1:分批删除(适用通用场景)
使用
LIMIT
分批次删除
避免单次事务过大导致锁表,每次删除后释放事务资源:sqlDELETE FROM large_table WHERE create_time < '2023-01-01' LIMIT 1000; -- 每次删除1000行
循环执行直到影响行数为0,建议每次删除后暂停(如1秒)以分散压力。
存储过程自动化
封装为存储过程,通过sleep
控制频率:sqlDELIMITER // CREATE PROCEDURE batch_delete() BEGIN DECLARE affected_rows INT DEFAULT 1; WHILE affected_rows > 0 DO DELETE FROM large_table WHERE create_time < '2023-01-01' LIMIT 1000; SET affected_rows = ROW_COUNT(); DO SLEEP(1); -- 控制删除频率 END WHILE; END // DELIMITER ;
方案2:分区表快速清理(需提前规划分区)
按时间分区
若表已按时间分区,可直接删除整个分区(DDL操作,效率极高):sqlALTER TABLE large_table DROP PARTITION p2022;
动态调整分区
定期通过REORGANIZE PARTITION
维护分区结构(需提前设计分区策略)。
方案3:归档后清理(保留历史数据)
- 迁移数据到归档表sql
CREATE TABLE archive_table LIKE large_table; INSERT INTO archive_table SELECT * FROM large_table WHERE create_time < '2023-01-01';
2. **删除原表数据**
结合方案1的分批删除,或直接通过分区删除。
#### **方案4:使用工具(推荐)**
- **pt-archiver(Percona Toolkit)**
安全归档并删除数据,避免锁表:
```bash
pt-archiver \
--source h=host,D=database,t=large_table,u=user,p=password \
--dest h=host,D=database,t=archive_table \
--where "create_time < '2023-01-01'" \
--progress 1000 \
--limit 1000 \
--txn-size 1000 \
--statistics
优势:逐批提交事务,自动控制频率,支持归档与删除并行。
三、清理后优化
- 回收表空间
- InnoDB引擎:执行
OPTIMIZE TABLE large_table;
(锁表,建议低峰操作)。 - 在线重建:使用
pt-online-schema-change
避免长时间锁表:bashpt-online-schema-change \ --alter "ENGINE=InnoDB" \ D=database,t=large_table \ --execute
更新统计信息
sqlANALYZE TABLE large_table;
监控与验证
- 检查表大小:
SHOW TABLE STATUS LIKE 'large_table';
- 确认业务功能正常,查询性能恢复。
四、高级场景处理
场景1:清理时避免主从延迟
- 从库延迟处理
若使用主从架构,可在从库暂停复制,清理后重新同步:sqlSTOP SLAVE; -- 执行清理操作 START SLAVE;
场景2:清理大文本/二进制字段
- 单独处理大字段
若表含BLOB/TEXT
字段,先清理大字段再删除行:sqlUPDATE large_table SET blob_column = NULL WHERE create_time < '2023-01-01'; -- 再执行分批删除
五、避坑指南
避免全表扫描
确保WHERE
条件能命中索引(如create_time
字段需有索引)。事务拆分
单次事务不宜过大,防止Undo日志膨胀(可设置innodb_undo_log_truncate=ON
)。谨慎使用
TRUNCATE
TRUNCATE TABLE
虽快,但无法按条件删除,且重置自增ID,可能影响业务。
总结
千万级大表清理的核心思路是化整为零,通过分批操作、分区优化或工具自动化分散压力。优先推荐使用 pt-archiver
或分批删除方案,配合分区表设计可大幅提升效率。清理后需及时回收空间并更新统计信息,确保数据库性能长期稳定。