MySQL索引对NULL值的处理
# 索引不会包含有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。这句的前半句是不对的(可参考官网说明: https://dev.mysql.com/doc/refman/5.7/en/is-null-optimization.html),但是后半句的结论确是可以采纳的。
虽然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. 参考好友王的文章,可以移步我们的站点查看详情: http://www.fordba.com/spend-10-min-to-understand-how-mysql-use-index.html
MySQL索引对NULL值的处理的更多相关文章
- mysql 索引列为Null的走不走索引及null在统计时的问题
要尽可能地把字段定义为 NOT NULL,即使应用程序无须保存 NULL(没有值),也有许多表包含了可空列(Nullable Column)这仅仅是因为它为默认选项.除非真的要保存 NULL,否则就把 ...
- 让索引包含null值的两种方法
1. 把有NULL值的列与一个常数,或者一个带有not null约束的列一同索引 create index ind_01 on t01(col01,1); 或者 create index ind_01 ...
- Mysql 关于处理NULL值的相关函数和操作符
操作符 <=> NULL-safe equal. This operator performs an equality comparison like the = operator, bu ...
- Mysql整数运算NULL值处理注意点
CleverCode近期在导出报表的时候,在整数做减法的时候,发现整数减去null得到是null.这是一个细节问题,希望大家以后注意. 1 表中的数据 total,used都是整形,同意为空. 2 有 ...
- 【转】Oracle索引列NULL值引发执行计划该表的测试示例
有时开发进行表结构设计,对表字段是否为空过于随意,出现诸如id1=id2,如果允许字段为空,因为Oracle中空值并不等于空值,有可能得到意料之外的结果.除此之外,最关键的是,NULL会影响oracl ...
- mysql中的null字段值的处理及大小写问题
在MySQL中,NULL字段的处理,需要注意,当在处理查询条件中有NULL,很有可能你得到的值不是想要的,因为,在MySQL中,判断NULL值相等(=)或者不等(!=)都会返回false.主要出现在常 ...
- MySQL中order by中关于NULL值的排序问题
MySQL中order by 排序遇到NULL值的问题 MySQL数据库,在order by排序的时候,如果存在NULL值,那么NULL是最小的,ASC正序排序的话,NULL值是在最前面的. 如果我们 ...
- MySQL的NULL值处理
我们已经知道MySQL使用 SQL SELECT 命令及 WHERE 子句来读取数据表中的数据,但是当提供的查询条件字段为 NULL 时,该命令可能就无法正常工作. 为了处理这种情况,MySQL提供了 ...
- MySQL NULL 值处理
MySQL NULL 值处理 我们已经知道MySQL使用 SQL SELECT 命令及 WHERE 子句来读取数据表中的数据,但是当提供的查询条件字段为 NULL 时,该命令可能就无法正常工作. 为了 ...
随机推荐
- Python之☞网络编程中一些概念问题(未完)
:::一些名词的解释::: 网络: 网络是辅助双方能够连接在一起的工具,使用网络的目的,为了联通多方然后进行通讯,能够让软件在不同的电脑上运行,相互传输数据. 网络协议: 约定俗成的,没有理由. TC ...
- LeetCode之找零钱
题目:已知不同面值的钞票,求如 何用最少数量的钞票组成某个金额,求可 以使用的最少钞票数量.如果任意数量的已知面值钞票都无法组成该金额, 则返回-1. 示例: Input: coins = [1, 2 ...
- 【随记】SQL Server配置管理器”远程过程调用失败“的问题解决
打开配置管理器时出现如下错误: 问题原因: 在电脑上安装vs2012.vs2013,vs2015.vs2017.vs2019时会安装[Express LocalDB] 解决方案: 卸载所有[XXXLo ...
- Function.apply.bind()与Function.apply.bind()
1.Function.apply.bind(…) 我在学习promise部分的时候遇到了这样的代码: Promise.resolve([10,20]).then(Function.apply.bind ...
- SpaceClaim脚本功能(Beta功能)
本操作仅适用ANSYS SpaceClaim 2016 打开SpaceClaim脚本编辑器的方法有两种 方法一(看截图操作): 方法二(请见后面的实例操作). 创建球体源代码: #定义 ...
- sql中的表值函数与标量值函数区别与用法
通俗来讲: 听名字就知道区别了 表值函数返回的是一张表结果,就和一个select查询语句一样,只不过里面带入了参数或者很复杂:标量值函数返回的只是一个值 一 .表值函数又分为内联函数与多语句函数 (1 ...
- CI框架常用函数(AR数据库操作的常用函数)
用户手册地址:http://codeigniter.org.cn/user_guide/index.html 1.查询表记录$this->db->select(); //选择查询的字段$t ...
- MAC 上抓取网页数据的工具有哪些?
我希望能够从网页上, 比如气象局数据, 财经数据等等, 我看到官方提供的数据都比较混乱, 有的是一个php文件, 有的是一个文本, 有的干脆不提供数据, 我想问, Mac上, 用什么工具去抓数据, 以 ...
- Android系统分区
Android系统开发时,经常会遇到添加或者调整系统分区大小的问题,下面以mstar的一款产品为例进行分析: (1)mount指令可以查看到板子中挂在的分区,主要关注ext4类型分区,例如tvserv ...
- python 连接ORacle11g
一,准备软件 (1)cx_Oracle (2)instantclient 注: (1)instantclient是Oracle客户端,plsql称为数据库第三方可视化工具,即便装了plsql也还是要装 ...