讲师中心 微信公众号
AI工具推荐 视频效率加速

MySQL如何优化涉及锁的慢查询_添加覆盖索引减少数据扫描

梦宇吖_4620

梦宇吖_4620

发布时间:2026-04-04 08:48:04

|

859人浏览过

|

来源于php中文网

原创

加索引仍被锁住是因为普通索引未覆盖查询字段,导致回表引发更长行锁或间隙锁;真正有效的覆盖索引需包含WHERE、ORDER BY和SELECT所有字段,且须通过EXPLAIN确认Extra为“Using index”。

mysql如何优化涉及锁的慢查询_添加覆盖索引减少数据扫描

为什么加了索引还是被锁住?

因为普通索引不覆盖查询字段,MySQL 在 WHERE 条件走索引后,仍要回表查 SELECT 的列——这个过程会触发更长的行锁(甚至升级为间隙锁),尤其在 UPDATE 或 SELECT ... FOR UPDATE 场景下特别明显。

常见错误现象:SHOW ENGINE INNODB STATUS 里看到大量 lock_mode X locks rec but not gap waiting,同时 EXPLAIN 显示 type = ref 但 Extra 有 Using index condition; Using where; Using filesort 或干脆没写 Using index。

  • 覆盖索引必须包含 WHERE、ORDER BY、SELECT 所有字段,缺一个就可能回表
  • 联合索引顺序很重要:等值条件字段放最左,范围条件(如 >、BETWEEN)放右,SELECT 列补在最后
  • 注意隐式类型转换:比如 user_id 是 VARCHAR,但查询用 WHERE user_id = 123(整数),会导致索引失效,锁范围扩大

怎么写出真正有效的覆盖索引?

不是“把所有字段塞进索引”就行。MySQL 的 B+ 树索引只在叶子节点存完整索引列值,覆盖索引的本质是让优化器能从这棵树上直接拿到全部需要的数据,不碰聚簇索引。

使用场景举例:高频执行的 SELECT status, created_at FROM orders WHERE user_id = ? AND status IN (?, ?) ORDER BY created_at DESC LIMIT 20,且常被 UPDATE ... WHERE user_id = ? AND status = ? 并发修改。

  • 正确建法:ALTER TABLE orders ADD INDEX idx_user_status_time (user_id, status, created_at) INCLUDE (status, created_at) —— 但注意 MySQL 8.0.13+ 才支持 INCLUDE;老版本得写成 (user_id, status, created_at, status, created_at)(重复列无害,但冗余)
  • 更稳妥的老版本写法:(user_id, status, created_at) —— 因为 SELECT 只要这两个字段,且 WHERE 和 ORDER BY 都命中了
  • 别把 TEXT 或超长 VARCHAR 放进索引:会截断或直接报错,且大幅增加 B+ 树层级,反而拖慢锁获取速度

哪些情况覆盖索引也救不了锁竞争?

覆盖索引能减少扫描和锁粒度,但不能消除锁本身。当多个事务操作同一索引范围时,冲突照旧发生。

MySQL
MySQL

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

下载

典型错误现象:QPS 不高,但 innodb_row_lock_waits 持续上涨,EXPLAIN 显示用了覆盖索引,SHOW PROFILE 却卡在 statistics 或 locking 阶段。

  • IN 子句参数过多(如 WHERE id IN (1,2,3,...,2000))会让优化器放弃使用索引,退化为全索引扫描 → 锁住整个索引范围
  • 使用函数或表达式:如 WHERE DATE(created_at) = '2024-01-01',即使 created_at 有索引,也无法走覆盖路径
  • 事务中混用 SELECT ... FOR UPDATE 和非覆盖查询:前一句走了覆盖索引,后一句查了没索引的字段,锁就从单行扩展到多行甚至间隙

验证是否真的“覆盖”了?

别信 EXPLAIN 里出现 key 就万事大吉。关键看 Extra 字段有没有 Using index —— 它表示“只用索引树,不回表”,这才是覆盖索引生效的铁证。

实操建议:

  • 执行 EXPLAIN FORMAT=TRADITIONAL SELECT status, created_at FROM orders WHERE user_id = 123 AND status = 'paid',确认 Extra 是 Using index,不是 Using where; Using index(后者可能仍需过滤)
  • 在测试库开两个会话:一个跑 SELECT ... FOR UPDATE,另一个立刻 UPDATE 同一主键 → 如果秒级返回而非等待,说明锁范围确实缩小了
  • 用 SELECT * FROM performance_schema.data_locks 查当前锁记录,对比加覆盖索引前后 LOCK_DATA 的值是否从多行变成单行或更窄范围

最容易被忽略的是:覆盖索引对 INSERT ... ON DUPLICATE KEY UPDATE 无效,因为唯一键冲突检测仍需访问聚簇索引,这时候锁行为和没索引几乎一样。

热门AI工具

更多
Seko
Seko Hot

一款AI视频创作工具,主要用于商汤科技推出的创编一体的AI短视频创作Agent,适合需要提升相关任务效率的用户。

讯飞智作

讯飞智作是一款AI视频创作工具,AI文本配音工具,数字人课程、营销视频制作。

Loomy
Loomy Hot

一款AI工具,主要用于科大讯飞发布的桌面级 AI 助理,比 OpenClaw 更易用、更安全!,适合需要提升相关任务效率的用户。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

Laper
Laper Hot

Laper是专为编剧、导演和制片人推出的 AI 原生剧本创作工具。

UpDream
UpDream Hot

一款AI视频创作工具,主要用于哔哩哔哩推出的自研AI视频创作工具,适合需要提升相关任务效率的用户。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

SkildArt
SkildArt Hot

SkildArt是一款AI文本写作工具,一站式 AI 视觉创作平台。

相关专题

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

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

4663

2023.10.12

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

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

971

2023.10.27

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

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

1229

2024.02.23

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

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

6661

2024.03.06

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

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

3403

2024.03.06

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

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

6640

2024.04.07

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

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

9161

2024.04.29

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

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

1230

2024.04.29

Vite 项目如何打包和部署
Vite 项目如何打包和部署

Vite项目打包部署专题汇集生产构建、产物预览、输出目录、资源路径、Nginx与GitHub Pages部署及常见白屏和路由404问题的已审核文章,帮助读者完成上线流程。

100

2026.10.28

热门下载

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

精品课程

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

共1课时 | 193人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn