Skip to content

针对 MySQL 千万级大表的数据清理,需兼顾性能、业务连续性、存储空间回收数据一致性。以下是分步骤的解决方案:


一、清理前的准备工作

  1. 明确清理规则
    与业务方确认数据保留策略(如保留近6个月数据),避免误删有效数据。

  2. 备份数据
    使用 mysqldump 或物理备份工具(如Percona XtraBackup)对目标表做全量备份:

    bash
    mysqldump -h host -u user -p database table > backup.sql
  3. 低峰期操作
    选择业务流量最低的时间段(如凌晨)执行清理,减少对线上服务的影响。


二、高效数据清理方案

方案1:分批删除(适用通用场景)

  • 使用 LIMIT 分批次删除
    避免单次事务过大导致锁表,每次删除后释放事务资源:

    sql
    DELETE FROM large_table 
    WHERE create_time < '2023-01-01' 
    LIMIT 1000;  -- 每次删除1000行

    循环执行直到影响行数为0,建议每次删除后暂停(如1秒)以分散压力。

  • 存储过程自动化
    封装为存储过程,通过 sleep 控制频率:

    sql
    DELIMITER //
    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操作,效率极高):

    sql
    ALTER TABLE large_table DROP PARTITION p2022;
  • 动态调整分区
    定期通过 REORGANIZE PARTITION 维护分区结构(需提前设计分区策略)。

方案3:归档后清理(保留历史数据)

  1. 迁移数据到归档表
    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

优势:逐批提交事务,自动控制频率,支持归档与删除并行。


三、清理后优化

  1. 回收表空间
  • InnoDB引擎:执行 OPTIMIZE TABLE large_table;(锁表,建议低峰操作)。
  • 在线重建:使用 pt-online-schema-change 避免长时间锁表:
    bash
    pt-online-schema-change \
      --alter "ENGINE=InnoDB" \
      D=database,t=large_table \
      --execute
  1. 更新统计信息

    sql
    ANALYZE TABLE large_table;
  2. 监控与验证

  • 检查表大小:SHOW TABLE STATUS LIKE 'large_table';
  • 确认业务功能正常,查询性能恢复。

四、高级场景处理

场景1:清理时避免主从延迟

  • 从库延迟处理
    若使用主从架构,可在从库暂停复制,清理后重新同步:
    sql
    STOP SLAVE;
    -- 执行清理操作
    START SLAVE;

场景2:清理大文本/二进制字段

  • 单独处理大字段
    若表含 BLOB/TEXT 字段,先清理大字段再删除行:
    sql
    UPDATE large_table 
    SET blob_column = NULL 
    WHERE create_time < '2023-01-01';
    -- 再执行分批删除

五、避坑指南

  1. 避免全表扫描
    确保 WHERE 条件能命中索引(如 create_time 字段需有索引)。

  2. 事务拆分
    单次事务不宜过大,防止Undo日志膨胀(可设置 innodb_undo_log_truncate=ON)。

  3. 谨慎使用 TRUNCATE
    TRUNCATE TABLE 虽快,但无法按条件删除,且重置自增ID,可能影响业务。


总结

千万级大表清理的核心思路是化整为零,通过分批操作、分区优化或工具自动化分散压力。优先推荐使用 pt-archiver 或分批删除方案,配合分区表设计可大幅提升效率。清理后需及时回收空间并更新统计信息,确保数据库性能长期稳定。

文章来源于自己总结和网络转载,内容如有任何问题,请大佬斧正!联系我