LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

千万级大表DELETE实战:业务卡死2小时后的血泪教训与优化方案

admin
2025年12月29日 22:5 本文热度 404
一、真实场景复现:一次DELETE引发的“业务雪崩”

背景:某电商平台需清理1000万条3年前的历史订单数据(表总数据量5000万+),开发直接执行 
DELETE FROM order_info WHERE create_time < '2022-01-01'

结果

  1. 业务卡死:DELETE逐行删除锁表2小时,用户无法下单,客服投诉量激增;

  2. 磁盘爆炸:undo log占满2TB磁盘,数据库宕机;

  3. 主从延迟:从库延迟从1秒飙升至3小时,财务结算中断。

核心问题

  • 锁表风险:DELETE逐行删除全程持锁,大事务导致业务不可用;

  • 资源消耗:千万级DELETE产生巨量redo/undo log,CPU和I/O压力骤增;

  • 无进度反馈:业务方无法感知删除进度,陷入“盲等焦虑”。


二、Java工程师必看:3种DELETE优化方案(附生产级代码)

方案1:LIMIT分批删除(推荐!)

适用场景需保留部分数据(如删除历史订单)。

优势

  • 零锁表:小批量提交,事务短,锁持有时间极短;

  • 可控性强:可动态调整批次大小,平衡性能与进度。

实现代码(MyBatis + PageHelper)

// 1. 分页删除(每批1万条) 
public void batchDelete() 
    int batchSize = 10000
    int totalDeleted = 0
    long startTime = System.currentTimeMillis(); 
    
    do { 
        // 分页查询待删除数据(按主键范围分页,避免全表扫描) 
        PageHelper.startPage(1, batchSize); 
        List<Order> orders = orderMapper.selectByCreateTimeBefore("2022-01-01"); 
        
        if (orders.isEmpty()) break
        
        // 批量删除(使用MyBatis批量操作) 
        SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH); 
        OrderMapper batchMapper = sqlSession.getMapper(OrderMapper.class); 
        for (Order order : orders) { 
            batchMapper.deleteById(order.getId()); 
        } 
        sqlSession.commit(); 
        sqlSession.close(); 
        
        totalDeleted += orders.size(); 
        log.info("已删除 {} 条,耗时 {} 秒", totalDeleted, (System.currentTimeMillis()-startTime)/1000); 
        Thread.sleep(500); // 降低数据库压力 
    } while (true); 
}

优化技巧

  • 索引优化:在WHERE条件字段(如create_time)上加索引,避免全表扫描;

  • 事务控制:每批提交事务,避免长事务占用连接池;

  • 进度监控:记录已删除量,暴露Prometheus监控指标。


方案2:表分区(极速删除)

适用场景:数据按时间/地域等维度自然分区(如日志表)。

优势

  • 秒级删除DROP PARTITION是元数据操作,零锁表;

  • 空间即时回收:物理删除分区文件,磁盘空间立即释放。

实现代码(Spring Boot + MyBatis)

// 1. 创建分区表(按月份分区) 
@Update("CREATE TABLE order_2024 (id INT PRIMARY KEY, ...) " + 
        "PARTITION BY RANGE (YEAR(create_time)) (" + 
        "PARTITION p202401 VALUES LESS THAN (202402))"
void createPartitionedTable()

// 2. 删除旧分区(业务低峰期执行) 
@Update("ALTER TABLE order DROP PARTITION p202312"
void dropPartition();

方案3:临时表重建(数据保留场景)

适用场景:需保留部分数据(如保留最近3个月)。

优势

  • 零锁表RENAME TABLE原子操作,业务无感知;

  • 高效重建:避免DELETE触发索引维护。

实现代码(Spring Batch)

// 1. 创建临时表并插入保留数据 
@Update("CREATE TABLE order_temp LIKE order"
void createTempTable()

@Update("INSERT INTO order_temp SELECT * FROM order WHERE create_time >= '2022-01-01'"
void copyData()

// 2. 原子切换表名 
@Update("RENAME TABLE order TO order_old, order_temp TO order"
void switchTables()

// 3. 异步清理旧表(后台线程执行) 
@Async
public void dropOldTable() 
    try { 
        Thread.sleep(60000); // 等待业务切换完成 
        orderMapper.dropTable("order_old"); 
    } catch (InterruptedException e) { 
        Thread.currentThread().interrupt(); 
    } 
}

三、避坑指南:Java工程师的DELETE血泪经验

  1. 绝对不要做

    • 直接执行无条件的DELETE FROM large_table→ 必锁表!

    • 在事务外执行DELETE → 事务超时引发回滚灾难。

  2. 必须监控

    • 数据库:SHOW ENGINE INNODB STATUS观察锁状态;

    • 业务:埋点记录删除进度,暴露Prometheus监控指标。

  3. 性能调优参数

# 降低DELETE对业务影响 
innodb_flush_log_at_trx_commit=2  # 牺牲部分数据安全换取速度 
innodb_io_capacity=2000           # 提升磁盘IO吞吐


阅读原文:原文链接


该文章在 2025/12/31 10:26:23 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2026 ClickSun All Rights Reserved