where id NOT IN(?,?,?) 会走索引吗?

文章目录

      • [1. 优化器不是"法律条文",而是"精算师"](#1. 优化器不是“法律条文”,而是“精算师”)
      • [2. 临界点:到底选哪种?](#2. 临界点:到底选哪种?)
      • [3. 拆解图中的例子](#3. 拆解图中的例子)
        • [情况 A:`WHERE num NOT IN (1, 2)`](#情况 A:WHERE num NOT IN (1, 2))
        • [情况 B:`WHERE num NOT IN (3)`](#情况 B:WHERE num NOT IN (3))
      • [4. 总结与口诀](#4. 总结与口诀)
      • [💡 进阶思考](#💡 进阶思考)

这张图解释了 MySQL 优化器的一个核心灵魂:成本准则(Cost-based Optimization)

很多人有个误区,觉得"NOT IN!=LIKE '%xxx' 肯定不走索引"。但实际上,MySQL 并不看心情,它只看数学。

为了让你彻底理解,我们要把这个逻辑拆成三层:


1. 优化器不是"法律条文",而是"精算师"

MySQL 优化器在执行每一条 SQL 前,都会在后台算两笔账:

  • 账本 A(走索引): 先去二级索引找 ID,拿到 ID 后再去主键索引找整行数据(这个动作叫"回表")。
  • 账本 B(全表扫描): 直接从头到尾把整张表的数据扫一遍。

重点来了:

二级索引是逻辑有序 的,但在磁盘上,回表去拿具体数据时往往是随机 I/O ;而全表扫描是顺序 I/O

对于磁盘来说,顺序读比随机读快得多


2. 临界点:到底选哪种?

优化器会估算一个"比例"。

  • 如果你的 NOT IN 过滤掉绝大部分数据,只剩下 1% 的数据需要查。
    • 优化器想: "回表只要回 1% 的次数,不麻烦,走索引吧!"
  • 如果你的 NOT IN 只过滤掉一点点,剩下 90% 的数据都要查。
    • 优化器想: "我要回表 90% 的行,这得在磁盘上跳来跳去 90 万次,我不如直接花点力气把整张表顺序读一遍呢!"

3. 拆解图中的例子

假设表里有 200 万零几行数据:

  • num = 1:有 100 万行
  • num = 2:有 100 万行
  • num = 3:只有 5 行
情况 A:WHERE num NOT IN (1, 2)
  • 含义: 实际上就是找 num = 3 的那 5 行。
  • 成本: 只需要通过索引找到这 5 行,然后回表 5 次。
  • 结果: 走索引。因为数据量极小,回表成本几乎为零。
情况 B:WHERE num NOT IN (3)
  • 含义: 实际上是找 num 为 1 和 2 的那 200 万行。
  • 成本: 要回表 200 万次!磁头会在磁盘上跳疯掉。
  • 结果: 不走索引(全表扫描)。优化器认为顺序读这 200 万行比跳着读更快。

4. 总结与口诀

这个知识点其实在讲 "索引的选择性(Selectivity)"

  • 什么时候走索引? 当过滤完剩下的数据**"少而精"**的时候。
  • 什么时候全表扫描? 当剩下的数据**"多而杂"**(通常超过全表的 20%~30%)的时候。

所以,不要记"NOT IN 不走索引",要记"剩下的太多就不走索引"。


💡 进阶思考

如果你查询的字段就在索引里 (覆盖索引),不需要回表,那么哪怕 NOT IN 剩下 99% 的数据,它也依然会走索引。因为不需要回表,随机 I/O 的痛点消失了。

相关推荐
Mahir0820 小时前
Redis 与 MySQL 数据同步:一致性保证的完整解决方案
数据库·redis·mysql·缓存·面试·数据一致性
·醉挽清风·21 小时前
学习笔记—MySQL—库表操作
笔记·学习·mysql
数据库小学妹1 天前
数据库连接池避坑指南:告别“连接超时”与“资源耗尽”,让系统跑得更快!
数据库·redis·sql·mysql·缓存·dba
前进的李工1 天前
EXPLAIN输出格式全解析:JSON、TREE与可视化
开发语言·数据库·mysql·性能优化·explain
达梦产品与服务1 天前
稳扎稳打,持续迭代 | SQLark V3.10 更新,30+ 项优化与修复
mysql·oracle·达梦数据库·pg·sqlark百灵连接
shizhan_cloud1 天前
MySQL 索引优化 + 慢查询日志
数据库·mysql
Drache_long1 天前
MySQL数据库(故障排除)
数据库·mysql
shaoming37761 天前
浏览器动作开发:地址栏图标点击事件、弹出页面设计
android·mysql·adb
Riu_Peter1 天前
【技术】Docker 部署 MySQL
mysql·adb·docker
Irene19911 天前
SQL示例:外键约束是关系型数据库中用于建立两个表之间链接的一种规则
mysql