mysql在高并发下如何优化索引更新_mysql锁策略与调整

酷杰姑娘_5821

酷杰姑娘_5821

2026-03-28

306人浏览

原创

update多导致索引变慢,因需同步维护b+树索引,引发页分裂、刷脏、唯一校验及锁争抢;应优化索引设计、启用change_buffering、避免全表扫描更新、合理使用upsert与锁策略。

mysql在高并发下如何优化索引更新_mysql锁策略与调整

为什么 UPDATE 一多,索引就变慢?

因为 MySQL 在更新带索引的字段时,不仅改数据行,还要同步维护 B+ 树索引结构——尤其是二级索引,每次 UPDATE 都可能触发页分裂、缓冲池刷脏、甚至唯一性校验。高并发下这些操作争抢 index latch 和 buffer pool mutex,锁等待直接堆起来。

实操建议:

MySQL
MySQL

编写正确的MySQL查询,避免字符集、索引和锁方面的常见陷阱。

下载
  • 避免在 WHERE 条件里用非索引字段更新索引字段(例如 UPDATE t SET status=1 WHERE name='xxx',而 name 没索引)——会全表扫描+逐行更新索引,锁住整张表
  • 把高频更新的列和查询条件列拆开:比如 status 经常变,但 created_at 几乎不变,就别把它们塞进同一个联合索引
  • 确认 innodb_change_buffering 开启(默认是 all),它能缓存非唯一二级索引的更新,减少随机 IO —— 但只对离散更新有效,批量顺序写反而可能降低收益

INSERT ... ON DUPLICATE KEY UPDATE 的锁范围比你想的大

这个语法看着像“存在就改,不存在就插”,实际执行时,InnoDB 会对 INSERT 尝试路径上的所有间隙(gap)加 INSERT_INTENTION 锁,并对命中记录加 X 锁。如果唯一索引冲突频繁,很容易卡在间隙锁等待上。

常见错误现象:Deadlock found when trying to get lock; try restarting transaction,尤其出现在按时间戳或自增 ID 批量 upsert 场景。

实操建议:

  • 确保冲突判断字段是 UNIQUE 或 PRIMARY KEY,否则会退化成全表扫描+行锁
  • 批量操作时,按主键升序排序后再提交,减少间隙锁交叉(例如先处理 id=100,再 id=200,而不是反过来)
  • 若只是想避免重复插入,且不关心是否真更新了,用 INSERT IGNORE 更轻量——它遇到唯一冲突直接跳过,不加 X 锁

什么时候该删掉二级索引?

不是所有 WHERE 条件都值得建索引。每多一个二级索引,INSERT/UPDATE/DELETE 就得多维护一棵树;更麻烦的是,MySQL 优化器可能因索引太多选错执行计划,反而让 UPDATE 变慢。

使用场景判断:

  • 单列索引只被用于等值查询(=),且该列更新频率 > 查询频率 → 删
  • 联合索引中,左边字段区分度极低(如 (is_deleted, user_id),is_deleted 只有 0/1)→ 考虑改成 (user_id, is_deleted) 或直接删
  • SELECT COUNT(*) FROM t WHERE x=1 这类查询,如果 x 更新极频繁,又没其他查询依赖该索引,不如用覆盖索引 + 快照统计替代

innodb_lock_wait_timeout 调小并不能解决根本问题

很多人一看到 Lock wait timeout exceeded 就立刻把 innodb_lock_wait_timeout 从 50 改成 5,以为能“快速失败”。其实这只是让事务更快报错,锁冲突本身还在——下游重试逻辑没跟上的话,QPS 一高照样雪崩。

真正要盯的是锁等待链源头:

  • 用 SELECT * FROM information_schema.INNODB_TRX 查长时间运行的事务
  • 结合 INNODB_LOCK_WAITS 和 INNODB_LOCKS(MySQL 5.7+ 已废弃,用 performance_schema.data_locks 替代)定位谁在等谁
  • 检查是否有长事务没提交(比如应用层开了事务但忘了 COMMIT),或者大事务在做 UPDATE 时锁住了热点行

索引更新的瓶颈往往不在 SQL 写法,而在数据分布和事务边界——比如一个订单状态流转,把“支付中→已支付”和“已支付→已发货”放在两个事务里,比塞在一个事务里锁得轻得多。

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

mysql

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

2023.10.12

3923

8

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.27

831

4

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

2024.02.23

1029

5

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

5761

10

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

2703

4

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

2024.04.07

5740

11

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

2024.04.29

7581

6

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

1030

5

sql中删除一列的命令是什么
sql中删除一列的命令是什么

在sql中,使用alter table语句可以删除一列,语法为:alter table table_name drop column column_name。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

912

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL vs MySQL
PostgreSQL vs MySQL

共1课时 | 178人学习

使用phpenv集成环境安装极致CMS
使用phpenv集成环境安装极致CMS

共2课时 | 282人学习