当前位置: 首页 > news >正文

MySQL中,IS NULL和IS NOT NULL不会走索引?错!

最近写了一系列关于MySQL索引相关的文章,帮大家系统全面地把索引这块的知识丰富串联起来,需要回顾或学习这方面的知识的朋友可以看看前面的文章。

今天这篇文章给大家分析和示例一下,MySQL中,当查询条件为IS NULLIS NOT NULL时,哪些情况会走索引,哪些情况下又不会走索引。最终结论可能与大家的直觉有所不同。

这篇文章会涉及到前面讲到的B+树相关的知识,请参考《MySQL之进阶:一篇文章搞懂MySQL索引之B+树》一文。

下面我们直接通过具体的实例来看看当查询条件为IS NULLIS NOT NULL时,索引的使用情况。

实例一:少量数据,使用索引

这里采用的MySQL数据库版本为8.0.18,后续实例均采用此版本。

创建一个test表,创建语句如下:

CREATE TABLE test (id INT PRIMARY KEY,col1 INT,col2 INT,INDEX idx_col1 (col1)
);-- 添加两条数据
insert into test values(1,null,1);
insert into test values(2,null,2);

其中在col1列上创建了索引。

实例演示

此时,我们来看IS NULLIS NOT NULL是否走索引。

mysql> explain SELECT * FROM test WHERE col1 IS NULL \G
*************************** 1. row ***************************id: 1select_type: SIMPLEtable: testpartitions: NULLtype: ref
possible_keys: idx_col1key: idx_col1key_len: 5ref: constrows: 1filtered: 100.00Extra: Using index condition

通过上面的EXPLAIN语句,我们可以看到,当查询条件为IS NULL,且对应查询条件字段上有索引时,MySQL使用索引来处理IS NULL查询条件。

再来看IS NOT NULL查询条件:

mysql> explain SELECT * FROM test WHERE col1 IS NOT  NULL \G
*************************** 1. row ***************************id: 1select_type: SIMPLEtable: testpartitions: NULLtype: range
possible_keys: idx_col1key: idx_col1key_len: 5ref: NULLrows: 1filtered: 100.00Extra: Using index condition

当查询条件为IS NOT NULL时,同样使用了索引。

在上面的示例中,我们可以看到无论是IS NULLIS NOT NULL都使用索引。

实例二:大量数据,少量NULL值

该实例依旧采用上述表结构,初始化3万数据,其中col1中的NULL值约占5%。

mysql> select count(*) from test;
+----------+
| count(*) |
+----------+
|    30000 |
+----------+

在上述情况下,我们再来看看两个查询语句的索引使用情况。

IS NULL查询条件:

mysql> explain SELECT * FROM test WHERE col1 IS NULL \G
*************************** 1. row ***************************id: 1select_type: SIMPLEtable: testpartitions: NULLtype: ref
possible_keys: idx_col1key: idx_col1key_len: 5ref: constrows: 1551filtered: 100.00Extra: Using index condition

可以看到,IS NULL查询条件使用了索引。

IS NOT NULL查询条件:

mysql> explain SELECT * FROM test WHERE col1 IS NOT  NULL \G
*************************** 1. row ***************************id: 1select_type: SIMPLEtable: testpartitions: NULLtype: ALL
possible_keys: idx_col1key: NULLkey_len: NULLref: NULLrows: 30570filtered: 50.00Extra: Using where

此时,IS NOT NULL查询条件在执行的过程中并没有使用索引,而是采用了全表扫描。

这是因为,当表中的大部分数据都满足 col1 IS NOT NULL 的条件(例如超过一半以上的记录符合条件,本实例中为95%),MySQL 的查询优化器可能会认为使用索引的代价高于全表扫描的代价,从而选择全表扫描。

实例三:大量数据,大量NULL值

该实例依旧采用上述表结构,初始化3万数据,其中col1中的NULL值约占95%。

在上述情况下,我们再来看看两个查询语句的索引使用情况。

IS NULL查询条件:

mysql> explain SELECT * FROM test WHERE col1 IS NULL \G
*************************** 1. row ***************************id: 1select_type: SIMPLEtable: testpartitions: NULLtype: ref
possible_keys: idx_col1key: idx_col1key_len: 5ref: constrows: 14957filtered: 100.00Extra: Using index condition

可以看到,IS NULL查询条件使用了索引。

IS NOT NULL查询条件:

mysql> explain SELECT * FROM test WHERE col1 IS NOT  NULL \G
*************************** 1. row ***************************id: 1select_type: SIMPLEtable: testpartitions: NULLtype: range
possible_keys: idx_col1key: idx_col1key_len: 5ref: NULLrows: 1558filtered: 100.00Extra: Using index condition

可以看到,IS NOT NULL查询条件也使用了索引。

通过上面的三个实例,我们可以看到,无论是IS NULLIS NOT NULL都是有可能使用索引的。这也证明了网络上一概而论并不正确。

下面,我们就具体分析一下IS NULLIS NOT NULL是否走索引的核心决定性因素。

索引是如何存储NULL值的?

在分析MySQL是否使用索引的原因之前,我们先要了解一下针对NULL值,在索引中是如何存储的。

在MySQL的InnoDB引擎中,聚簇索引一般是以主键作为存储依据,主键列的值不能为NULL。所以,针对这种情况,不存在NULL值存储的问题。

对于非聚簇索引中的NULL值,在大多数数据库实现中,NULL值在索引结构中有以下特点:

  • B+树的排序:NULL值通常被看作是最小值,因此索引存储中,NULL会排在树的最左边。
  • 链表形式存储:B+树叶子节点存储数据的引用,而叶子节点之间是顺序链接的,也就是说,包含NULL的记录会集中在最左侧,沿着链表可以顺序读取这些记录。
  • 查找NULL值:当查询列值为NULL时,数据库的索引机制可以通过扫描树的最左侧开始查找所有NULL值。

关于聚簇索引和非聚簇索引的相关知识,可以参考《学习MySQL绕不开的两个基础概念:聚集索引与非聚集索引》一文。

索引失效的原因

通过上面关于NULL值索引的存储,我们可以看到,在MySQL的InnoDB数据引擎中,NULL也是“有序”的,也可以通过索引(从最左侧开始)进行查找的。大多数关系型数据库也都支持对 NULL 值进行索引。

而真正决定IS NULLIS NOT NULL是否走索引的前提是索引能够显著降低执行成本。在MySQL中,查询优化器会根据执行成本决定是否使用索引,而不是单纯地因为 NULLIS NULL 的条件导致索引失效。

例如:

  • 如果通过索引查询的结果集非常大(例如大多数记录都为 NULL),那么索引命中的数据需要大量回表才能获取完整的记录,这种情况下,优化器可能会选择全表扫描,因为全表扫描的代价会更低。
  • 如果通过索引可以显著减少数据访问和回表的次数(例如查询结果集很小或者覆盖索引被使用),MySQL一般会选择使用索引。

关于回表的内容可参考《MySQL中,什么是回表查询,如何避免和优化?》一文。

因此,关于NULL值索引失效,有以下相关结论:

  • NULL 值可以走索引,但是否使用索引取决于具体的执行成本。
  • IS NULLIS NOT NULL 本身不会直接导致索引失效,优化器会根据数据量和数据分布动态选择索引或全表扫描。
  • 非聚簇索引通常需要回表,回表成本过高时,优化器可能放弃索引。
  • 查询性能优化需要结合具体的场景和数据分布分析,而不能简单地说某些条件下索引会失效。

小结

通过上面的示例我们可以看到,在MySQL中,查询条件使用IS NULLIS NOT NULL,理论上都会走索引。部分不走索引的情况也是因为优化器判断全表扫描的效率要高于使用索引,才导致放弃使用索引,而这与查询条件为IS NULLIS NOT NULL本身没有直接关系,只和执行成本有关。

所以,针对IS NULLIS NOT NULL是否走索引,不能一概而论,还是要回归到数据构成本身,当然,原则上MySQL是会选择走索引的。

http://www.dtcms.com/a/463213.html

相关文章:

  • 云网站注册怎么做网站文章
  • 用织梦做网站后面可以改吗网站建设需要购买服务器么
  • 手机做网站软件wix和wordpress哪个好
  • C++ const 用法全面总结与深度解析
  • 哪块行业需要网站建设自己装修怎么出设计图
  • 网站建设流程讯息中国舆情网官网
  • 西安网站建设和推广公司做会计要关注什么网站
  • 律师做推广宣传的网站开发工具的种类及使用方法
  • js class定义类,私有属性,类继承,子类访问父类的方法,重写父类的方法
  • AD21创建集成库
  • 做暧视频网站大全佛山企业名录黄页
  • jmeter接口测试该怎么做?
  • 10.9总结
  • 自己怎么用h5做网站久久结婚网
  • 住房和城乡建设局网站如何制作一个网页链接
  • 网站开发需求表安康市移动公司
  • 如何做网站的网页网站怎么升级
  • 网站的版式设计网络营销讲师培训
  • 郑州网站公司排名河北网站制作多少钱
  • 贵州移动端网站建设外贸网站定制开发
  • 文明网站建设方案及管理制度网站建设从零开始教程
  • 适合html初学者做的网站企业做网站建设
  • 类的定义和使用
  • 山东省城乡和住房建设厅网站做网站客户要提供什么
  • 多种语言的网站中国建设银行安徽省 招聘信息网站
  • 20. 有效的括号,394.字符串解码,739.每日温度,84. 柱状图中最大的矩形
  • 购物网站建设优缺点模板app
  • 大模型旋转位置编码
  • 注册万网后网站怎么赚钱的佛山关键词排名效果
  • 奎文建设局网站海南网络