当前位置: 代码网 > it编程>数据库>Mysql > MySQL中OR查询为什么会导致索引失效

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

2026年09月10日 Mysql 我要评论
要彻底理解这句话,我们需要把它拆成两个核心问题:为什么 or 经常导致索引失效? 以及 index merge(索引合并)到底是怎么把失效的索引救回来的?前提设定:假设我们有一张 user 表,里面有

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

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

前提设定:

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

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

假设你的 sql 是:

select * from user where name = '张三' or address = '北京'

server层的思考过程:

  • “我看到条件里有 name = '张三',可以用索引 a 极速查出来。”
  • “但是,条件是 or(或者),意味着我还得找出所有 address = '北京' 的人。”
  • “address 这个字段没有索引。为了找到所有北京的人,我别无选择,只能命令 innodb 把整张表从头到尾全扫描一遍(全表扫描)。”
  • 终极决定: “既然无论如何都要把整张表扫描一遍才能找齐 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 进行优化。”

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

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

为什么说是“可能”?

因为 mysql 的优化器(server层)会计算成本(cost-based optimization)。

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

到此这篇关于mysql中or查询为什么会导致索引失效的文章就介绍到这了,更多相关mysql or查询索引失效内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com