MySQL: OR查询为什么会导致索引失效

要彻底理解这句话,我们需要把它拆成两个核心问题:

为什么 OR 经常导致索引失效? 以及 Index Merge(索引合并)到底是怎么把失效的索引救回来的?


前提设定:

假设我们有一张 user 表,里面有 id(主键)、name(建了索引 A)、phone(建了索引 B)、address没建索引)。


1. 为什么用 OR 经常导致索引失效?

假设你的 SQL 是:

SELECT * FROM user WHERE name = '张三' OR address = '北京'

Server层的思考过程:

  1. "我看到条件里有 name = '张三',可以用索引 A 极速查出来。"

  2. "但是,条件是 OR(或者) ,意味着我还得找出所有 address = '北京' 的人。"

  3. "address 这个字段没有索引。为了找到所有北京的人,我别无选择,只能命令 InnoDB 把整张表从头到尾全扫描一遍(全表扫描)。"

  4. 终极决定: "既然无论如何都要把整张表扫描一遍才能找齐 address = '北京' 的人,那我一开始去查 name 索引还有什么意义呢?纯属脱裤子放屁。干脆直接全表扫描吧!"

结论: 只要 OR 连接的条件里,有哪怕一个条件没有有效索引,整个查询就会放弃所有索引,直接全表扫描。这就是俗称的"OR 导致索引失效"。


2. 什么是 Index Merge(索引合并)?

现在,我们把 SQL 换成 OR 两边都有索引的情况:

SELECT * FROM user WHERE name = '张三' OR phone = '13800000000'

在老版本的 MySQL(5.0 之前)里,引擎很死板:一次查询一张表,只能挑一个索引使用 。它要是挑了 name 索引,phone 字段就得全表扫描;它要是挑了 phone 索引,name 就得全表扫描。结果就是:照样全表扫描。

为了解决这个智障问题,MySQL 引入了 Index Merge(索引合并) 优化。


server 现在的战术变成了这样:

  • 第一步:并发查树(各找各的)

    Server 层命令 InnoDB:"你现在去走 name 索引树,把所有叫张三的主键 ID 给我找出来;同时,你去走 phone 索引树,把尾号 0000 的主键 ID 也找出来。"

    • 结果 A: name 索引查到了张三的主键集合 -> {ID: 1, 5, 8}

    • 结果 B: phone 索引查到了手机号的主键集合 -> {ID: 5, 9}

  • 第二步:在内存中合并去重(Merge)

    InnoDB 把这两波 ID 交给 Server 层(或者引擎层内部的 Handler)。程序在内存里把这两个集合做一个并集(Union)并去重:

    {1, 5, 8} ∪ {5, 9} = {1, 5, 8, 9}

  • 第三步:集中回表(一网打尽)

    拿着这个最终去重后的 ID 集合 {1, 5, 8, 9},去主键索引树里(聚簇索引)执行回表,把这 4 个人的完整数据一口气拿出来,返回给 Spring Boot。

3. 核心总结与注意事项

"当 OR 查询时,如果每个 OR 条件都能够使用有效索引,MySQL 可能会使用 Index Merge 进行优化。"

  1. "每个 OR 条件都能够使用有效索引": 这是触发合并的硬性前提。缺一个,就会退化成全表扫描。

  2. "进行优化": 指的是把两次索引扫描拿到的主键 ID 取并集,然后再统一回表,避免了全表扫描。

  3. 为什么说是"可能"?

    • 因为 MySQL 的优化器(Server层)会计算成本(Cost-based Optimization)。

    • 如果它发现你的表里一共就 100 条数据,它会觉得:"搞两棵树分别查,再在内存里去重并集,这套杂技算下来比我直接全表扫描还费劲。"这时候,它即使能用 Index Merge,也会主动放弃,选择全表扫描。

相关推荐
‎ദ്ദിᵔ.˛.ᵔ₎13 小时前
MySQL 表约束
数据库·mysql
linmengmeng_131415 小时前
【总结】MyBatis-Plus批量插入与清表的正确姿势
java·spring boot·mysql·mybatis
达梦数据17 小时前
DMDRS空间数据类型说明:Oracle、DM8、MySQL空间数据类型映射
数据库·mysql·oracle
lusklusklusk17 小时前
Oracle索引组织表,SQLServer聚集索引,Mysql Innodb表的数据行不是在磁盘上像排队一样严格连续地存放
mysql·postgresql·oracle·sqlserver
螺蛳粉 螺蛳粉19 小时前
mysql的备份与恢复
linux·运维·数据库·mysql
计算机毕设定制辅导-无忧学长20 小时前
《基于SpringBoot的中学教师数字胜任力测评网站的设计与实现》
java·vue.js·spring boot·mysql·中学教师数字胜任力测评网站
guo_wen_qiang21 小时前
mysql中有哪些日志
数据库·mysql
天天喝旺仔1 天前
MySQL索引优化实战:B+Tree原理、索引失效与覆盖索引调优
数据库·sql·mysql·性能优化
lqg_zone1 天前
CentOS 7 虚拟机磁盘 I/O 卡顿排查实录:从 iostat 异常到虚拟盘后端故障的完整定位
linux·服务器·mysql·centos