# 索引不会包含有NULL值的列
只要列中包含有NULL值都将不会被包含在索引中,复合索引中只要有一列含有NULL值,那么这一列对于此复合索引就是无效的。所以我们在数据库设计时不要让字段的默认值为NULL。

在很多库表设计规范、某某军规的文章中,是不是经常会看到类似这样的内容。小编也经常看到这样的内容,并且在编写规范的时候,准备也把这一条加进去。但在按部就班之余,小编抽空验证了一下,发现事实却并非如此!

小编使用的MySQL版本是社区版 5.7.21

新建测试表 t1,插入不含NULL值得100行数据,然后插入1行带NULL的数据 insert into t1(id) values(101); 表中有主键id,索引a

CREATE TABLE `t1` (`id` int(11) NOT NULL,`a` int(11) DEFAULT NULL,`b` int(11) DEFAULT NULL,PRIMARY KEY (`id`),KEY `a` (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

测试1,包含NULL单列索引的查询,可以看到即使是查找 IS NULL的行,也是可以用上索引的

测试1:desc select * from t1 where a > 82;
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+-----------------------+
| id | select_type | table | partitions | type  | possible_keys | key  | key_len | ref  | rows | filtered | Extra                 |
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+-----------------------+
|  1 | SIMPLE      | t1    | NULL       | range | a             | a    | 5       | NULL |   18 |   100.00 | Using index condition |
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+-----------------------+desc select * from t1 where a is NULL;
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-----------------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref   | rows | filtered | Extra                 |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-----------------------+
|  1 | SIMPLE      | t1    | NULL       | ref  | a             | a    | 5       | const |    1 |   100.00 | Using index condition |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-----------------------+desc select * from t1 where a = 20 or a is null;
+----+-------------+-------+------------+-------------+---------------+--------+---------+-------+------+----------+--------------------------+
| id | select_type | table | partitions | type        | possible_keys | key    | key_len | ref   | rows | filtered | Extra                    |
+----+-------------+-------+------------+-------------+---------------+--------+---------+-------+------+----------+--------------------------+
|  1 | SIMPLE      | t1    | NULL       | ref_or_null | idx_ab        | idx_ab | 5       | const |    2 |   100.00 | Using where; Using index |
+----+-------------+-------+------------+-------------+---------------+--------+---------+-------+------+----------+--------------------------+

注意对 NULL 值的检索只能使用 is null / is not null / <=>,不能使用=,<,>这样的运算符(mysql中可以用a <=> NULL 表示查找 a is NULL'的行)

测试2,包含NULL复合索引的查询,首先加一个复合索引 alter table t1 drop index a,add index idx_ab(a,b); 可以看到不管是指定 a is null ,或者指定 b is null ,都可以利用上索引 idx_ab(key_len 可以看出)

测试2:desc select * from t1 where a=50 and b>20;
+----+-------------+-------+------------+-------+---------------+--------+---------+------+------+----------+--------------------------+
| id | select_type | table | partitions | type  | possible_keys | key    | key_len | ref  | rows | filtered | Extra                    |
+----+-------------+-------+------------+-------+---------------+--------+---------+------+------+----------+--------------------------+
|  1 | SIMPLE      | t1    | NULL       | range | idx_ab        | idx_ab | 10      | NULL |    1 |   100.00 | Using where; Using index |
+----+-------------+-------+------------+-------+---------------+--------+---------+------+------+----------+--------------------------+desc select * from t1 where a=50 and b is null;
+----+-------------+-------+------------+------+---------------+--------+---------+-------------+------+----------+--------------------------+
| id | select_type | table | partitions | type | possible_keys | key    | key_len | ref         | rows | filtered | Extra                    |
+----+-------------+-------+------------+------+---------------+--------+---------+-------------+------+----------+--------------------------+
|  1 | SIMPLE      | t1    | NULL       | ref  | idx_ab        | idx_ab | 10      | const,const |    1 |   100.00 | Using where; Using index |
+----+-------------+-------+------------+------+---------------+--------+---------+-------------+------+----------+--------------------------+desc select * from t1 where a is null and b>20;
+----+-------------+-------+------------+-------+---------------+--------+---------+------+------+----------+--------------------------+
| id | select_type | table | partitions | type  | possible_keys | key    | key_len | ref  | rows | filtered | Extra                    |
+----+-------------+-------+------------+-------+---------------+--------+---------+------+------+----------+--------------------------+
|  1 | SIMPLE      | t1    | NULL       | range | idx_ab        | idx_ab | 10      | NULL |    1 |   100.00 | Using where; Using index |
+----+-------------+-------+------------+-------+---------------+--------+---------+------+------+----------+--------------------------+desc select * from t1 where a is null and b is null;
+----+-------------+-------+------------+------+---------------+--------+---------+-------------+------+----------+--------------------------+
| id | select_type | table | partitions | type | possible_keys | key    | key_len | ref         | rows | filtered | Extra                    |
+----+-------------+-------+------------+------+---------------+--------+---------+-------------+------+----------+--------------------------+
|  1 | SIMPLE      | t1    | NULL       | ref  | idx_ab        | idx_ab | 10      | const,const |    1 |   100.00 | Using where; Using index |
+----+-------------+-------+------------+------+---------------+--------+---------+-------------+------+----------+--------------------------+

由此,只要列中包含有NULL值都将不会被包含在索引中,复合索引中只要有一列含有NULL值,那么这一列对于此复合索引就是无效的。所以我们在数据库设计时不要让字段的默认值为NULL。这句的前半句是不对的(可参考官网说明: MySQL :: MySQL 5.7 Reference Manual :: 8.2.1.13 IS NULL Optimization),但是后半句的结论确是可以采纳的。

虽然MySQL可以在含有null的列上使用索引,但不代表null和其他数据在索引中是一样的。不建议列上允许为空,最好限制 not null ,并设置一个默认值,比如0和''空字符串等,如果是datetime类型,可以设置成'1970-01-01 00:00:00'这样的值。对MySQL来说,null 是一个特殊的值,Conceptually, NULL means “a missing unknown value” and it is treated somewhat differently from other values。 对null做算术运算的结果都是null,count时不会包括null行,null 比空字符串需要更多的存储空间等。

附:上面说到可用通过 key_len 看出使用了索引列的个数,a,b 都是 int 类型,4 byte,为什么 key_len 是 5 byte 和 10 byte 呢?是因为如果索引列定义时允许NULL,其key_len还需要再加 1 bytes. 参考好友王的文章,可以移步我们的站点查看详情: 10分钟让你明白MySQL是如何利用索引的 | | For DBA

MySQL索引对NULL值的处理相关推荐

  1. mysql中与null值不能比较

    在mysql中,选择某field为不等于某值的时候,使用<>符号.但查bug时发现该field为null的并不能查出来. 查原因为: null值不能与其他值进行比较,只能使用is null ...

  2. mysql 索引列为Null的走不走索引及null在统计时的问题

    要尽可能地把字段定义为 NOT NULL,即使应用程序无须保存 NULL(没有值),也有许多表包含了可空列(Nullable Column) 这仅仅是因为它为默认选项.除非真的要保存 NULL,否则就 ...

  3. Oracle技术之索引与Null值对于Hints及执行计划的影响

    由于B*Tree索引不存储Null值,所以在索引字段允许为空的情况下,某些Oracle查询不会使用索引. 很多时候,我们看似可以使用全索引扫描(Full Index Scan)的情况,可能Oracle ...

  4. mysql文件导出NULL值处理_Mysql select into outfile NULL值导出的处理方法

    目录 1简介... 1 2 准备... 1 2.1 环境说明... 1 3 安装... 2 4 配置... 2 5 使用... 2 5.1 验证实验... 2 5.2 问题分析... 4 6 延展.. ...

  5. MySql中的NULL值和空值

    定义: 空值:表示一个空字符或零长度的字符串,可以使用空引号""来表示: NULL值:MySql中,NULL表示缺少一个已知或适当的值. 除了整数类型的列外,所有其他类型的列(包括 ...

  6. MYSQL查询空值/NULL值

     select * from XXXX where YYYY is NULL

  7. mysql左连接null值丢失、条件不起作用的问题

    一.问题 在mysql左连接时, 写上where时,空值丢失,数据减少 不写where,只用and连接,主表条件不起作用,数据变多. 二.错误复现 1.当使用where+条件时,左连接查询空值丢失 S ...

  8. Mysql数据唯一约束与唯一索引案例总结及踩坑记(含NULL值与唯一约束唯一索引的搭配使用)

    Mysql数据唯一索引与唯一约束案例总结 唯一约束的说明 唯一约束是约束(CONSTRAINT)里的一种,常见的还有主键.外检.默认值.是否为空.检查等.唯一约束即限制某个或某些字段具有唯一性(不能重 ...

  9. mysql null 排前面_Mysql实现null值排在最前/最后的方法示例

    前言 我们已经知道 MySQL 使用 SQL SELECT 命令及 WHERE 子句来读取数据表中的数据,但是当提供的查询条件字段为 NULL 时,该命令可能就无法正常工作. 为了处理这种情况,MyS ...

最新文章

  1. 【ACM】杭电OJ 5055(Bob and math problem)
  2. 当前分支上有未提交的更改时签出另一个分支
  3. Hyperledger Fabric 链码(2) 接口
  4. 纯Python包发布setup脚本编写示例
  5. Linux 之八 完整嵌入式 Linux 环境、(交叉)编译工具链、CPU 体系架构、嵌入式系统构建工具
  6. iOS Hacker Keychain相关The executable was signed with invalid entitlements
  7. 最新PHP秒赞,快乐秒赞 php版
  8. layui-概念-入门-总结
  9. WebBrowser控件禁用超链接转向、脚本错误提示、默认右键菜单和快捷键
  10. T-SQL | 逻辑查询处理内幕学习
  11. dns是指网络域名系统_域名系统(DNS)是Internet的骨干。 这就是全部的运作方式。...
  12. 英语对IT从业者的影响
  13. 一键查询快递物流单号,分析提前签收
  14. pmp十大知识领域,49个过程的4W1H
  15. 正态分布的峰度和偏度分别为_偏度与峰度的正态性分布判断
  16. 从零开始学习CANoe(四)—— 设计panel
  17. Mysql之账号管理、建库以及四大引擎【入门篇】
  18. Oracle -PL/SQL Developer错误解决方案(ORA-02291)
  19. MyEclipse使用Maven创建web项目+搭建SSM框架教程
  20. 分析洋葱模型实现原理,在自己项目中接入洋葱模型

热门文章

  1. 三次握手和四次挥手之间的关系
  2. Web前端开发笔记——第二章 HTML语言 第二节 基本标签
  3. OpenStack的部署T版(七)——cinder模块
  4. linux jrdmm 命令 局部 编译,Cgminer-4.10.0 Linux 挖矿
  5. java多语言编程语言_为什么很多程序员信仰“Java是世界上最好的编程语言”
  6. arcgis导入excel数据_ArcGIS批量导入数据
  7. Java和C/C++程序实时通讯数据移植问题的研究
  8. 计算机模型机设计实验报告,基本模型机设计与实现 实验报告
  9. mysql命令查看过程内容_mysql查看存储过程命令
  10. 计算机文化基础性考二,电大计算机文化基础形考二答案