Lazy loaded image
MySQL
🐬is null、 not null ≠
Words 1398Read Time 4 min
2025-7-24
2025-7-25
type
Post
status
Published
date
Jul 24, 2025
slug
equal
summary
MySQL
tags
MySQL
category
MySQL
icon
password
原文
这里单独拿三个条件是来说明一个问题,mysql 用is null is not null 不能使用索引的观点。

事前准备

注意这里的mysql版本为5.7.43

is null

数据状况为: 在t表中总共有18条数据,其中三条key1的数据的值为null。
优化器在执行真正的查询前,会少量访问索引数据,确认key1 (null,null)这个区间有多少条数据,经过调查得知,需要扫描的的二级记录占总比率为3/16,它觉得这个查询使用key1这个索引查询比较靠谱,所以在执行计划里使用idx_key1这个索引来执行查询。

not null

数据状况: 在t表中总共有18条数据,其中三条key1的数据的值为null。
优化器在执行真正的查询前,会访问少量索引数据,确认key1(null,+∞)这个区间有多少条数据。经过调查得知,需要扫描的二级记录占比为13/16,它觉得这个比例已经很大了,所以优化器决定使用全表扫描的方式来执行查询。
如何让not null 使用该索引呢?
很简单,只要让符合 not null的条件的数据多起来就可以使用该索引去查询。
此时优化器再去执行真正的查询前,会访问少量的索引数据,确认key1(null,+∞)这个区间有多少条数据。经过调查得知,需要扫描的二级记录占比为3/16
它觉得这个使用key1索引查询比较靠谱,所以使用索引去查询。

数据状况: 总共16条数据。其中为null的值16条,不为null的3条。
优化器在执行真正的查询前,会访问少量的索引数据,确认 key1(null,80), (80,+∞) 这两个区间的有多少条记录。经过调查得知,需要扫描的二级记录占比为3/16 ,它觉得使用key1这个索引比较靠谱,所以使用该计划去执行查询。
为什么是3/16? 明明应该是2/16 (null,80)的记录数量为0,(80,+∞)区间的记录为2
(null,80) 这个区间一条数据没有,但是mysql在设计优化器的时候决定当某个扫描区间符合给定条件的记录数量为0时,硬生生的让它为1,也就是说它优化器认为(null,80)这个区间的扫描记录数量为1。
 
上一篇
时间轮算法
下一篇
索引

Comments
Loading...