Mysql索引下推、索引跳跃、索引覆盖的具体使用

 更新时间:2026年04月23日 11:07:48   作者:电魂泡哥  
本文主要介绍了Mysql索引下推、索引跳跃、索引覆盖的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

1.索引覆盖(Covering Index)

索引覆盖的意思就是直接从索引中获取所有需要的字段,跳过回表(即根据索引找到主键后再去数据表查一遍)的步骤。
EXPLAIN标志:Using index。
需要SELECT的字段全部被包含在使用的索引中。

  • 典型场景:需要频繁查询某几个固定字段,且这些字段能组成一个复合索引。

  • 应用示例:例如,一个商品摘要的列表页只需要 name 和 image、price字段。

    -- 查询所需字段 (name, image,price) 完全被索引 idx_product 覆盖
    EXPLAIN SELECT name, image,price FROM product WHERE p_id = 10086;

效果:如果使用SELECT *,MySQL需要先通过idx_product 找到主键,再回表到数据页获取其他字段(如amountnote),多了一次随机I/O。而使用索引覆盖,数据直接从索引页返回,性能更高.

2.索引下推(Index Condition Pushdown, ICP)

索引下推的意思就是将WHERE条件中可被索引覆盖的部分下推到存储引擎层进行过滤,减少存储引擎层向上层(Server层)返回的数据量,从而减少回表次数。
适用于二级索引,且WHERE条件中包含索引中非最左前缀列的过滤条件。
EXPLAIN标志:Using index condition。

-- idx_status  (p_id, status) 用于查找,amount > 100 在索引中无法判断,但会被“下推”
SELECT * FROM product WHERE p_id = 10086 AND status = 'PAID' AND amount > 1000;

传统方式会先通过索引找到所有p_id=10086 AND status='PAID'的行的主键,然后逐一回表检查amount > 1000。启用ICP后,MySQL会在存储引擎层利用索引遍历数据,如果某行不满足amount > 1000,就直接跳过,连主键ID都不会取,更不会发起回表请求。这显著减少了无效回表的次数。

3.索引合并 (Index Merge)

查询条件中包含了多个字段,且每个字段都有独立的单列索引,但没有合适的复合索引。
Using intersect(...)Using union(...)Using sort_union(...)
仅适用于单表,不适用于全文索引
对同一个表使用多个索引,分别扫描后将结果合并(取交集、并集等)

-- WHERE 条件中使用了 OR 连接两个不同索引的字段
SELECT * FROM product WHERE p_id = 10086 OR create_time > '2024-01-01';

MySQL会同时使用idx_product(虽然此索引包含p_id列)和idx_create_time这两个索引,分别找到满足各自条件的行的主键ID,然后将这两个ID集合合并(取并集),最后再回表。这避免了只能使用其中一个索引而导致另一个条件被全表扫描的情况。
注意:有可能会碰到死锁情况。
循环更新操作。Index Merge的两个扫描路径(路径1路径2)的执行可能存在微小的时序差异,导致不同事务在相同SQL下的锁获取顺序不同。

具体来说:

  • 事务A循环更新M1时,可能先扫描idx_material_id,再扫描idx_delivery_docs_no
  • 事务B循环更新M2时,可能先扫描idx_delivery_docs_no,再扫描idx_material_id
  • 这种差异虽然不影响最终结果,但会影响加锁的先后顺序
  • typeindex_merge ← 确认使用了Index Merge
  • keyidx_picking_docs_no,idx_material_id ← 同时使用两个索引

优化方案:
使用联合索引 (最佳),批量更新操作,强制使用索引。

核心要点

  1. Index Merge不是万能的: 虽然能优化某些场景,但也可能带来锁顺序不确定性
  2. 联合索引优于Index Merge: 对于固定的多条件查询,联合索引是最佳选择
  3. 批量操作优于循环: 无论索引如何,批量SQL都比循环UPDATE性能更好
  4. EXPLAIN是好帮手: 出现性能问题时,第一时间查看执行计划

避免Index Merge导致问题的建议

  1. 优先建立联合索引: 根据高频查询的WHERE条件设计
  2. 避免过多单列索引: 容易误导优化器
  3. 使用索引提示: 必要时强制使用指定索引
  4. 批量操作代替循环: 减少SQL执行次数
  5. 定期分析执行计划: 及时发现Index Merge的不合理使用

4.索引跳跃扫描 (Index Skip Scan, ISS)

Using index for skip scan。
MySQL 8.0.13 引入,适用于前导列唯一值较少的场景。
查询条件不包含联合索引的最左前缀列时,也能使用该索引。

-- 查询条件 status = 'PAID' 跳过了联合索引 idx_user_status 的最左列 user_id
SELECT * FROM product WHERE status = 'PAID';

在MySQL 8.0之前,此查询无法使用idx_status。ISS优化器会“智能地”将其拆分为若干个子查询,例如:SELECT ... WHERE user_id=1 AND status='PAID' UNION SELECT ... WHERE user_id=2 AND status='PAID' ...,从而有效利用索引。但它的生效前提是,被跳过的列(user_id)的不同取值数量要比较少。

多范围读取 (Multi-Range Read)

Using MRR
主要用于范围查询Join操作
将二级索引查到的主键ID(Row IDs)先放入缓冲区排序,再按顺序回表访问。

-- 通过 create_time 索引进行范围查询,可能得到大量主键ID
SELECT * FROM product WHERE create_time BETWEEN '2026-01-01' AND '2026-01-31';

idx_create_time索引中存储的主键ID(p_id)可能是无序的。如果直接回表,会导致大量的随机I/O。启用MRR后,MySQL会先将这些主键ID收集到内存的read_rnd_buffer中并排序,然后再按顺序批量回表访问数据页,将随机I/O转化为顺序I/O,极大提升了I/O效率.

到此这篇关于Mysql索引下推、索引跳跃、索引覆盖的具体使用的文章就介绍到这了,更多相关Mysql索引下推、索引跳跃、索引覆盖内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Mysql启动报错Error1045(28000)的原因分析及解决

    Mysql启动报错Error1045(28000)的原因分析及解决

    这篇文章主要介绍了Mysql启动报错Error1045(28000)的原因分析及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2025-04-04
  • SQL CREATE INDEX提高数据库检索效率的关键步骤详解

    SQL CREATE INDEX提高数据库检索效率的关键步骤详解

    这篇文章主要为大家介绍了SQL CREATE INDEX提高数据库检索效率的关键步骤详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-12-12
  • sql语句示例之case when作为where条件

    sql语句示例之case when作为where条件

    这篇文章主要给大家介绍了关于sql语句示例之case when作为where条件的相关资料,在SQL语句中CASE WHEN子句是根据条件表达式的结果来执行不同的逻辑操作,它使用在WHERE子句中,以根据特定的条件在查询结果中过滤数据,需要的朋友可以参考下
    2023-08-08
  • Mysql分库分表实现方式

    Mysql分库分表实现方式

    这篇文章详细介绍了分库分表的概念,原因,如何实现,以及不同中间件的优缺点,同时,也介绍了如何进行数据迁移和扩容缩容,以及如何处理分库分表后的ID和事务问题
    2025-02-02
  • MySQL分区表的最佳实践指南

    MySQL分区表的最佳实践指南

    这篇文章主要给大家介绍了关于MySQL分区表的最佳实践指南,文中通过示例代码介绍的非常详细,对大家学习或者使用MySQL具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2020-05-05
  • MySQL运行报错:“Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggre”解决方法

    MySQL运行报错:“Expression #1 of SELECT list is not in GR

    这篇文章主要给大家介绍了关于MySQL运行报错:“Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggre”的解决方法,文中将解决方法介绍的非常详细,需要的朋友可以参考下
    2022-06-06
  • ERROR 1862 (HY000): Your password has expired. To log in you must change it using a .....

    ERROR 1862 (HY000): Your password has expired. To log in you

    当你在安装 MySQL过程中,通过mysqld --initialize 初始化 mysql 操作后,生成临时密码后,没有直接进行 MySQL连接,中途重启服务或者重启机器等,导致密码失效问题,怎么处理呢,感兴趣的朋友一起看看吧
    2019-11-11
  • Mysql服务器的启动与停止(二)

    Mysql服务器的启动与停止(二)

    Mysql服务器的启动与停止(二)...
    2006-11-11
  • MySQL中进行SQL调优的方法步骤

    MySQL中进行SQL调优的方法步骤

    文章主要介绍了SQL调优的方法,包括合理设计索引、避免使用SELECT*、避免函数计算、避免使用%LIKE、满足最左匹配原则、避免对无索引字段进行排序以及利用缓存来优化,需要的朋友可以参考下
    2025-11-11
  • Mysql连接无效(invalid connection)问题及解决

    Mysql连接无效(invalid connection)问题及解决

    这篇文章主要介绍了Mysql连接无效(invalid connection)问题及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-02-02

最新评论