港真,Null 貌似在那边都是个头疼的问题,好比 Java 里让人头疼的 NullPointerException,为了制止猝不及防的空指针异常,千百年来措施猿们不得不在代码里小心翼翼的各类 if 判定,贫苦而又臃肿,为此 java8 引入了 Optional 来制止这一问题。
下面咱们要聊的是 MySQL 里的 null,在大量的 MySQL 优化文章和书籍里都提到了字段尽大概用NOT NULL,而不是NULL,除非非凡环境。但却都只给结论不说明原因,犹如鸡汤不给勺子一样,让不少初学者对这个结论将信将疑可能云里雾里。本文本日就具体的分解下利用 Null 的原因,并给出一些不消 Null 的来由。
1、NULL 为什么这么多人用?
2、是不是以谣传讹?
MySQL 官网文档:
NULL columns require additional space in the rowto record whether their values are NULL. For MyISAM tables, each NULL columntakes one bit extra, rounded up to the nearest byte.
Mysql难以优化引用可空列查询,它会使索引、索引统计和值越发巨大。可空列需要更多的存储空间,还需要mysql内部举办非凡处理惩罚。可空列被索引后,每笔记录都需要一个特另外字节,还能导致MYisam 中牢靠巨细的索引酿成可变巨细的索引。
—— 出自《高机能mysql第二版》
照此阐明,还真不是以谣传讹,这是有理论依据和出处的。
3、给我一个不消 Null 的来由?
(1)所有利用NULL值的环境,都可以通过一个有意义的值的暗示,这样有利于代码的可读性和可维护性,并能从约束上加强业务数据的类型性。
(2)NULL值到非NULL的更新无法做到原地更新,昆山软件开发,更容易产生索引破裂,从而影响机能。
留意:但把NULL列改为NOT NULL带来的机能提示很小,除非确定它带来了问题,不然不要把它当成优先的优化法子,最重要的是利用的列的范例的适当性。
(3)NULL值在timestamp范例下容易出问题,出格是没有启用参数explicit_defaults_for_timestamp
(4)NOT IN、!= 等负向条件查询在有 NULL 值的环境下返回永远为空功效,查询容易堕落
create table table_2 ( `id` INT (11) NOT NULL, user_name varchar(20) NOT NULL ) create table table_3 ( `id` INT (11) NOT NULL, user_name varchar(20) ) insert into table_2 values (4,"zhaoliu_2_1"),(2,"lisi_2_1"),(3,"wangmazi_2_1"),(1,"zhangsan_2"),(2,"lisi_2_2"),(4,"zhaoliu_2_2"),(3,"wangmazi_2_2") insert into table_3 values (1,"zhaoliu_2_1"),(2, null) -- 1、NOT IN子查询在有NULL值的环境下返回永远为空功效,查询容易堕落 select user_name from table_2 where user_name not in (select user_name from table_3 where id!=1) mysql root@10.48.186.32:t_test_zz5431> select user_name from table_2 where user_name not -> in (select user_name from table_3 where id!=1); +-------------+ | user_name | |-------------| +-------------+ 0 rows in set Time: 0.008s mysql root@10.48.186.32:t_test_zz5431> -- 2、单列索引不存null值,复合索引不存全为null的值,假如列答允为null,昆山软件开发,大概会获得“不切合预期”的功效集 -- 假如name答允为null,索引不存储null值,功效会合不会包括这些记录。所以,请利用not null约束以及默认值。 select * from table_3 where name != 'zhaoliu_2_1' -- 3、假如在两个字段举办拼接:好比题号+分数,首先要各字段举办非null判定,不然只要任意一个字段为空城市造成拼接的功效为null。 select CONCAT("1",null) from dual; -- 执行功效为null。 -- 4、假如有 Null column 存在的环境下,昆山软件开发,count(Null column)需要分外留意,null 值不会参加统计。 mysql root@10.48.186.32:t_test_zz5431> select * from table_3; +------+-------------+ | id | user_name | |------+-------------| | 1 | zhaoliu_2_1 | | 2 | <null> | | 21 | zhaoliu_2_1 | | 22 | <null> | +------+-------------+ 4 rows in set Time: 0.007s mysql root@10.48.186.32:t_test_zz5431> select count(user_name) from table_3; +--------------------+ | count(user_name) | |--------------------| | 2 | +--------------------+ 1 row in set Time: 0.007s -- 5、留意 Null 字段的判定方法, = null 将会获得错误的功效。 mysql root@localhost:cygwin> create index IDX_test on table_3 (user_name); Query OK, 0 rows affected Time: 0.040s mysql root@localhost:cygwin> select * from table_3 where user_name is null\G ***************************[ 1. row ]*************************** id | 2 user_name | None 1 row in set Time: 0.002s mysql root@localhost:cygwin> select * from table_3 where user_name = null\G 0 rows in set Time: 0.002s mysql root@localhost:cygwin> desc select * from table_3 where user_name = 'zhaoliu_2_1'\G ***************************[ 1. row ]*************************** id | 1 select_type | SIMPLE table | table_3 type | ref possible_keys | IDX_test key | IDX_test key_len | 23 ref | const rows | 1 Extra | Using where 1 row in set Time: 0.006s mysql root@localhost:cygwin> desc select * from table_3 where user_name = null\G ***************************[ 1. row ]*************************** id | 1 select_type | SIMPLE table | None type | None possible_keys | None key | None key_len | None ref | None rows | None Extra | Impossible WHERE noticed after reading const tables 1 row in set Time: 0.002s mysql root@localhost:cygwin> desc select * from table_3 where user_name is null\G ***************************[ 1. row ]*************************** id | 1 select_type | SIMPLE table | table_3 type | ref possible_keys | IDX_test key | IDX_test key_len | 23 ref | const rows | 1 Extra | Using where 1 row in set Time: 0.002s mysql root@localhost:cygwin>