大事务的代价:为什么一个长事务能拖垮整库

王

王DBA

· 阅读 260

分享

数据库突然整体变慢,连接数飙升、大量请求超时,排查半天发现根源是一笔跑了十分钟还没提交的事务。大事务的破坏力常常超出直觉:它不只是自己慢,还会拖累所有与它相关的查询,甚至影响到从库和备份。

长事务为什么危险

  • 锁持有时间过长:事务里持有的行锁要等到提交或回滚才释放。一个长事务会让后续访问相同数据的请求排队等待,等待链条一旦形成,连接池很快被占满,看起来就像整库挂了。
  • undo 无法及时清理:只要还有活跃事务需要旧版本数据,历史版本就不能被回收。长事务会导致 undo 空间持续膨胀,占用磁盘并拖慢需要读取历史版本的查询。
  • 回滚代价极高:修改了大量数据的事务一旦失败,回滚可能比正向执行还慢。此时既不能强行终止,也不能继续等待,处置空间非常有限。
  • 放大主从延迟:大事务在从库上通常需要整体回放,回放期间从库的可见数据落后,读写分离的业务会读到旧值。
  • 影响备份与 DDL:物理备份和某些结构变更都需要等待事务边界,长事务会让备份窗口失控,或让在线 DDL 长时间卡住。
大事务的代价:为什么一个长事务能拖垮整库

怎么发现长事务

日常巡检应该固定关注几个地方:当前活跃事务的列表与已持续时间、锁等待关系(谁在等谁)、事务中已修改的行数、连接池中处于非空闲状态的连接数。把这些做成看板与告警,比等到业务报障再查有效得多。

告警阈值建议按业务实际情况设定:多数在线交易类事务应该在很短时间内完成,持续时间明显超出正常范围的事务就值得立刻查看,而不是等到分钟级才响应。

常见的成因

  • 事务里夹了远程调用:在事务中间调用 HTTP 接口、发送消息、写外部存储,一旦对方变慢,事务就被拖住。这是最常见也最容易忽视的原因。
  • 批量操作不分批:一次更新几十万行、一次导入全量数据,没有拆分成小批次提交。
  • 事务范围写大了:把只读查询、参数校验、日志写入都包进事务里,实际只有两三行数据需要保护。
  • 人工操作忘提交:在客户端手动执行了更新语句却没有提交,会话一直挂着。这类问题在排查时很容易被忽略。
  • 连接池使用不当:手动获取连接后没有在异常路径上正确释放或回滚。
大事务的代价:为什么一个长事务能拖垮整库

拆事务的实操建议

原则是:事务只包住必须原子的那部分操作,其余全部移到事务外。

  • 先算后写:把查询、校验、远程调用、数据组装全部放在事务开始之前完成,事务里只保留写入语句。
  • 批量分片:大批量更新拆成小批次循环提交,每批控制在合理行数,批次之间留出间隔,给从库回放和锁释放留时间。
  • 异步解耦:非核心动作(发通知、写日志、更新统计)改成事务提交后通过消息或异步任务处理,不要占用事务时间。
  • 明确边界:使用框架的声明式事务时,注意方法内部自调用不会生效、事务嵌套的传播行为等细节,避免以为有事务其实没有,或以为范围小其实很大。
  • 补偿代替长事务:跨服务的业务一致性用最终一致方案(消息、对账、补偿),不要试图用一个数据库事务包住多个系统的操作。

结构变更与大表操作

大表的索引增删与结构变更同样要评估影响:执行期间的锁范围、产生的临时空间、对主从延迟的冲击。建议放在业务低峰执行,并提前准备回退方案。对超大表,优先考虑支持在线变更的方式,并在变更前后对比执行计划,确认索引按预期生效。

把巡检固化下来

长事务治理不是一次专项,而是常态巡检的一部分。建议把「活跃事务时长」「锁等待数量」「undo 空间增长」「从库延迟」四项纳入日常看板,并为每一项设置告警。多数拖垮整库的事故,在早期都有明显的信号,只是没有人看。

小结:事务越短越好,这不是性能优化的技巧,而是数据库稳定性的基本要求。把远程调用、批量处理、非核心逻辑移出事务,绝大多数锁等待问题会自然消失。

需要外部支持时,可以找安徽卓牛

针对数据库性能与稳定性问题,安徽卓牛可以结合阿里云数据库与存储产品体系,协助客户完成现状排查、架构评估、优化实施与上线后的持续运维,全程由具备阿里云认证资质的技术团队跟进。具体方案与费用以实际评估和报价为准,可通过官网在线客服联系安徽卓牛。

#MySQL#事务#锁等待#undo#性能优化