港真,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>