mysql 大表数据备份,新手教程

📅 2026/7/5 13:50:47
mysql 大表数据备份,新手教程
这是一个非常经典且务实的MySQL数据治理方案。只保留近6个月热数据、将旧数据按年归档备份在运维上被称作“滚动切分”与“冷热分离”。具体的操作不能简单地用DELETE会锁表且性能极差而应该采用“搬移-归档-清理”的标准化流程。下面是一套可直接落地的操作指南1. 核心策略采用“表交换”而非“删数据”最稳妥的方式是创建归档表将旧数据从主表“剥离”出去而不是逐行删除。假设你的主表叫orders时间字段是create_time。第一步创建当年或某一年的归档表结构必须与主表完全一致但可以去掉一些不必要的二级索引以提升写入速度主键保留。-- 例如归档 2025 年的数据 CREATE TABLE orders_archive_2025 LIKE orders; -- 删除归档表上的非必要索引可选提升插入速度 ALTER TABLE orders_archive_2025 DROP INDEX idx_user_id, DROP INDEX idx_status;第二步将旧数据“搬移”至归档表原子操作使用RENAME TABLE实现表交换这是MySQL中唯一能做到“瞬间挪移”且不阻塞业务的方法。但注意这一步要求时间分界线恰好落在某个整点或整日且业务上允许短暂的表不存在通常在凌晨做。如果你需要严格按create_time 2026-01-01搬移更安全的方式是分批次插入删除但在MySQL 5.6推荐使用pt-archiver工具如果没有就用纯SQL事务批量搬移-- 1. 先将旧数据插入归档表分批执行每批1000条 INSERT INTO orders_archive_2025 SELECT * FROM orders WHERE create_time 2026-01-01 AND create_time 2025-01-01 LIMIT 1000; -- 2. 确认插入成功后再从主表删除这批数据务必带相同条件 DELETE FROM orders WHERE create_time 2026-01-01 AND create_time 2025-01-01 LIMIT 1000;重要务必在create_time字段上建立索引否则删除和查询会全表扫描拖垮数据库。建议写脚本循环执行如每2秒跑一次避开业务高峰期。2. 进阶方案使用pt-archiverDBA首选如果你有Percona Toolkit这是最安全、最优雅的方式。它会自动将数据从主库拷贝到归档库并以小块chunk的形式删除彻底避免锁表。pt-archiver \ --source h主库IP,D数据库名,torders \ --dest h备份库IP,D数据库名,torders_archive_2025 \ --where create_time 2026-01-01 \ --limit 1000 \ --txn-size 1000 \ --purge \ --progress 10000 \ --statistics--purge表示从源表删除已归档的数据。--txn-size每1000条提交一次事务对业务影响极小。3. 最后一步释放物理磁盘空间关键注意即使你删除了主表里的几百万条数据MySQL的ibd数据文件并不会自动缩小磁盘空间不会释放给操作系统。你需要执行表空间碎片整理-- 在业务低峰期执行会锁表 OPTIMIZE TABLE orders;或者使用ALTER TABLE orders ENGINEInnoDB;效果相同。执行完后磁盘空间才会真正空出来。4. 按年备份的落地建议你提到的“按年备份”不建议只放在MySQL里因为归档表在MySQL里依然占用昂贵的SSD存储。更合理的流程是主库只留近6个月表orders。归档库同一台机器或另一台低配机器存放近3-5年的归档表orders_archive_2024orders_archive_2025。对象存储/冷存储将超过3年的数据用mysqldump或mydumper导出为 SQL/CSV 文件使用gzip压缩后压缩率可达90%上传至阿里云OSS或AWS S3的“归档存储”类型成本极低。导出冷数据的示例命令# 导出2024年数据并压缩 mysqldump -u用户名 -p 数据库名 orders_archive_2024 | gzip /backup/orders_2024.sql.gz # 确认导出无误后删除该归档表 DROP TABLE orders_archive_2024;5. 可能遇到的“坑”与对策常见问题解决方案主从延迟批量删除数据会产生大量binlog导致从库延迟。建议将LIMIT设小如500并增加--sleep参数如休眠1秒。查询必须带时间分表后应用代码必须改写SQLWHERE条件必须包含create_time否则查询会扫描全表因为数据只留6个月不带时间查会扫大量空页。6个月零1天的数据怎么办建议写一个定时任务如每月1号凌晨执行CALL archive_procedure();将create_time DATE_SUB(NOW(), INTERVAL 6 MONTH)的数据自动搬移。自增ID断层归档后主表ID会断层这不影响业务。如果使用分布式ID雪花算法完全没影响。6、演示示例6.1 复制表CREATE TABLE t_order_package_2024 LIKE t_order_package;//复制表结构并创建新表6.2 获取数据段的最小ID最大IDSELECT min(id),max(id) FROM t_order_package WHERE date 2025-01-01 AND date 2024-01-01;//记录最小ID最大ID6.3 分段复制数据INSERT INTO t_order_package_2024 SELECT * FROM t_order_package WHERE (id 1 and id 10) and (date 2025-01-01 AND date 2024-01-01);//分批复制数据大批量容易锁表6.4 分段删除数据DELETE FROM t_order_package WHERE id 2236979 LIMIT 1000;//不要大批量删除容易锁表6.5 释放物理磁盘空间OPTIMIZE TABLE t_order_package;7. 总结执行路径凌晨2点业务低峰期。执行pt-archiver或脚本将半年前的数据搬移到orders_archive_2025。执行OPTIMIZE TABLE orders释放空间。将orders_archive_2025迁移至低配归档数据库。将2年前的归档表导出压缩上传至云冷存储并删除库内对应表。如果你的数据量极大上百亿单纯靠脚本删除可能依然很慢需要引入分区表Partitioning配合“交换分区”来瞬间剥离数据。你想了解一下基于时间分区的“秒级剥离”方案吗我可以为你展开讲讲。