当前位置: 首页 > news >正文

【数据库】tdsql(mysql8.0)慢sql优化思考二

一次月度绩效核算批量插入,从 10 分钟陡增至 13 分钟仍未完成。没有改过 SQL,没有加过索引,备份任务恰好在跑…… 但真相往往藏在最不起眼的参数里。


一、现象:熟悉的 SQL 突然“不认人”了

每月月初,业务老师会触发一次绩效核算,底层逻辑是一条INSERT INTO ... SELECT的大批量插入语句,将源表数据处理后写入目标表。过去一直稳定在10 分钟左右完成,但这个月却跑了超过 13 分钟仍未结束。

第一反应是“是不是刚好碰上备份任务在跑,I/O 抢占了?”——但直觉不能替代证据,用数据说话。


二、定位:用 sys 快速“揪出”真凶 SQL

既然目标表是target_table,直接查询performance_schema中按 SQL 指纹汇总的统计信息,找出耗时最长的相关语句:

SELECTDIGEST_TEXT,COUNT_STAR,SUM_TIMER_WAIT,AVG_TIMER_WAITFROMperformance_schema.events_statements_summary_by_digestWHEREDIGEST_TEXTLIKE'%target_table%'ORDERBYSUM_TIMER_WAITDESCLIMIT1;

很快拿到了该 SQL 的DIGEST(指纹标识),随后便可以精确追踪它的执行细节。


三、执行计划没毛病,但“耗时”露了馅

MySQL 8.0 提供的EXPLAIN ANALYZE不仅能展示预估计划,还能真实输出每个阶段的实际执行耗时,比传统EXPLAIN直观得多:

EXPLAINANALYZEINSERTINTOtarget_table(id,col1,col2,...)SELECTNULL,col1,col2,...FROMsource_tableWHERE...;

结果让人困惑:

  • 索引使用正常,扫描行数合理;
  • 但“插入”阶段耗时极高,并且伴随大量锁等待提示。

这说明瓶颈不在查询,而在写入过程中的锁竞争


四、抓现行:锁等待事件“一锤定音”

借助sys.innodb_lock_waits视图,一眼就能看到当前谁在等锁、等什么锁:

SELECT*FROMsys.innodb_lock_waits;

输出中赫然出现了多个会话同时等待AUTO-INC表级锁。再配合performance_schema.data_locks确认,对象正是target_table的自增主键索引。

至此,疑点聚焦于自增列(AUTO_INCREMENT)的锁机制


五、自增锁的三种模式

MySQL 通过参数innodb_autoinc_lock_mode控制自增 ID 分配时的加锁策略,它直接决定了批量插入的并发性能。

模式值名称行为适用场景
0传统模式(traditional)所有INSERT均持表级AUTO-INC锁,直到语句结束兼容旧版本,安全性最高但并发最差
1连续模式(consecutive)简单插入(行数确定)用轻量互斥锁;INSERT ... SELECT等批量插入仍退化表级锁MySQL 8.0 之前的默认值,兼顾性能与安全
2交错模式(interleaved)所有插入均使用互斥锁,不再持有表级锁8.0 默认,并发性能最佳,但基于 STATEMENT 复制时需注意

为什么INSERT ... SELECT在模式 1 下会退化?
因为 MySQL 在语句执行前无法预知 SELECT 会返回多少行,为了保证连续分配且不与其它插入冲突,只能采用表级锁来“独占”自增生成器,直到整条语句执行完毕。

用一张流程图来梳理排查过程:

0 或 1

2

发现批量插入变慢

用 sys 定位 SQL 指纹

EXPLAIN ANALYZE 查看实际耗时

发现插入阶段锁等待严重

查询 sys.innodb_lock_waits

锁定 AUTO-INC 表级锁

检查 innodb_autoinc_lock_mode

当前模式?

瓶颈:批量插入退化表级锁

排查其他因素

调整为模式 2

压测验证 & 上线


六、现场检查与调整

登录数据库,执行:

SHOWVARIABLESLIKE'innodb_autoinc_lock_mode';

返回值为1——这正是症结所在。该实例是从 MySQL 5.7 升级而来,保留了旧版默认值,导致每月大批量插入时频繁发生表级锁争用。

立即在线调整(无需重启):

SETGLOBALinnodb_autoinc_lock_mode=2;

提醒:如果binlog_format仍是STATEMENT,交错模式可能造成主从数据不一致(因为自增值分配顺序不可预测)。但当前生产普遍使用ROW格式,此风险可控。可通过SHOW VARIABLES LIKE 'binlog_format'确认。


七、压测验证:数据说话

在测试环境准备相同表结构和数据量,对比两种模式下的插入耗时:

模式数据量耗时
模式 1(连续)150 万行16 分 52 秒
模式 2(交错)146 万行14 分 12 秒

耗时缩短约10%~15%,且在高并发下提升会更明显。生产环境应用调整后,当月核算任务回归正常,问题终结。


八、反思与 takeaways

  1. 备份 ≠ 元凶
    不要被同时运行的任务带偏,监控数据才是唯一可靠的裁判。

  2. 执行计划不变 ≠ 性能不变
    计划只反映“怎么查”,不反映“怎么等”。锁等待往往藏在执行计划的“额外信息”之外。

  3. 等待事件是排障的“第一性原理”
    sys.innodb_lock_waits能让你瞬间看到阻塞源,比漫无目的地看系统指标高效得多。

  4. 版本升级 ≠ 参数升级
    MySQL 8.0 虽然默认innodb_autoinc_lock_mode=2,但升级上来的实例会保留旧参数。务必主动检查,尤其涉及大批量INSERT ... SELECT的业务。

  5. 参数调整未必需要重启,但需要评估复制影响
    在线SET GLOBAL即可生效,只要确认 binlog 格式为 ROW,便可放心切换。


http://www.jsqmd.com/news/1232857/

相关文章:

  • 生成式AI与传统AI的本质区别:从模式映射到世界模拟
  • ROS中为PR2添加场景物体:MoveIt!空间建模实战指南
  • Claude Desktop 部署与核心功能体验:本地AI助手集成指南
  • Java集成YOLOv8实现工业质检的高性能优化实践
  • C#中的接口、枚举和结构体
  • 【电赛打怪连载3】CCS下的MSPM0G3507——封装好的代码如何移植适配???
  • Python机器学习入门:环境配置与核心算法实战
  • JDK 8 与 JDK 11 全面对比:从语言特性到生产选型
  • 我花 600 元用 AI 做了一个本地优先的个人财务管理 App——技术选型与核心实现
  • 二叉树的几道题
  • 2026大厂高频面试题:“AI都能写80%代码了,公司还要你干嘛?”
  • Gemini 3.1 Pro多模态AI与Windows 11系统构建解析
  • OpenClaw:AI代码生成与审核重构开发流程
  • 司法文书与案例检索系统——从裁判文书网到司法知识图谱的全链路实战
  • SEO成本优化实战:从工具到策略的全方位指南
  • Spring Boot高并发支付宝支付系统设计与实战
  • Fable 5:从AI打字机到智能经理的五大核心能力解析
  • Windows 11 24H2下eNSP兼容性问题解决方案
  • C++指令集优化实战:从编译器选项到SIMD内联汇编的性能飞跃
  • C++进制转换算法精解:从原理到竞赛实战,攻克大数与任意进制难题
  • Unity XR交互开发实战:从官方示例到自定义交互的完整指南
  • IL2CPP环境下游戏翻译失效的全面排查与修复指南
  • 微软Office 2024新特性解析与订阅制替代方案
  • 机器学习生产化:从模型上线到系统稳定性的工程实践
  • 中级游戏后端的逆袭之路——常规游戏功能设计(四、帮派系统)
  • 国产CAN总线产品选型与设计实践指南
  • TypeScript 7.0 正式发布 + TanStack Start 实战:2026 全栈开发者的新标配
  • 状态压缩BFS:从迷宫寻路到带锁钥匙问题的算法建模与C++实现
  • 使用POCO C++库构建高效HTTP客户端:从同步到异步的完整指南
  • 如何用AI在3小时内生成专业级中文字体:从零开始的完整指南