在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
通常能听到的答案是使用了NULL值的列将会使索引失效,但是如果实际测试过一下,你就知道IS NULL会使用索引.所以上述说法有漏洞. 着急的人拉到最下边看结论 Preface
NULL值是一种对列的特殊约束,我们创建一个新列时,如果没有明确的使用关键字not null声明该数据列,Mysql会默认的为我们添加上NULL约束. Introduce
NULL并不意味着什么都没有,我们要注意 NULL 跟 ''(空值)是两个完全不一样的值.MySQL中可以操作NULL值操作符主要有三个.
Example Null never returns true when comparing with any other values except null with “<=>”. (root@localhost mysql3306.sock)[zlm]>create table test_null( -> id int not null, -> name varchar(10) -> ); Query OK, 0 rows affected (0.02 sec) (root@localhost mysql3306.sock)[zlm]>insert into test_null values(1,'zlm'); Query OK, 1 row affected (0.00 sec) (root@localhost mysql3306.sock)[zlm]>insert into test_null values(2,null); Query OK, 1 row affected (0.00 sec) (root@localhost mysql3306.sock)[zlm]>select * from test_null; +----+------+ | id | name | +----+------+ | 1 | zlm | | 2 | NULL | +----+------+ 2 rows in set (0.00 sec) (root@localhost mysql3306.sock)[zlm]>select * from test_null where name=null; Empty set (0.00 sec) (root@localhost mysql3306.sock)[zlm]>select * from test_null where name is null; +----+------+ | id | name | +----+------+ | 2 | NULL | +----+------+ 1 row in set (0.00 sec) (root@localhost mysql3306.sock)[zlm]>select * from test_null where name is not null; +----+------+ | id | name | +----+------+ | 1 | zlm | +----+------+ 1 row in set (0.00 sec) (root@localhost mysql3306.sock)[zlm]>select * from test_null where null=null; Empty set (0.00 sec) (root@localhost mysql3306.sock)[zlm]>select * from test_null where null<>null; Empty set (0.00 sec) (root@localhost mysql3306.sock)[zlm]>select * from test_null where null<=>null; +----+------+ | id | name | +----+------+ | 1 | zlm | | 2 | NULL | +----+------+ 2 rows in set (0.00 sec) //null<=>null always return true,it's equal to "where 1=1". Null means “a missing and unknown value”.Let's see details below. (root@localhost mysql3306.sock)[zlm]>SELECT 0 IS NULL, 0 IS NOT NULL, '' IS NULL, '' IS NOT NULL; +-----------+---------------+------------+----------------+ | 0 IS NULL | 0 IS NOT NULL | '' IS NULL | '' IS NOT NULL | +-----------+---------------+------------+----------------+ | 0 | 1 | 0 | 1 | +-----------+---------------+------------+----------------+ 1 row in set (0.00 sec) //It's not equal to zero number or vacant string. //In MySQL,0 means fasle,1 means true. (root@localhost mysql3306.sock)[zlm]>SELECT 1 = NULL, 1 <> NULL, 1 < NULL, 1 > NULL; +----------+-----------+----------+----------+ | 1 = NULL | 1 <> NULL | 1 < NULL | 1 > NULL | +----------+-----------+----------+----------+ | NULL | NULL | NULL | NULL | +----------+-----------+----------+----------+ 1 row in set (0.00 sec) //It cannot be compared with number. //In MySQL,null means false,too. It truns null as a result if any expression contains null value. (root@localhost mysql3306.sock)[zlm]>select ifnull(null,'First is null'),ifnull(null+10,'First is null'),ifnull(concat('abc',null),'First is null'); +------------------------------+---------------------------------+--------------------------------------------+ | ifnull(null,'First is null') | ifnull(null+10,'First is null') | ifnull(concat('abc',null),'First is null') | +------------------------------+---------------------------------+--------------------------------------------+ | First is null | First is null | First is null | +------------------------------+---------------------------------+--------------------------------------------+ 1 row in set (0.00 sec) //null value needs to be disposed with ifnull() function,what usually causes sql statement more complex. //As we all know,MySQL does not support funcion index.Therefore,indexes on the column may not be used.That's really worse. It's diffrent when using count(*) & count(null column). (root@localhost mysql3306.sock)[zlm]>select count(*),count(name) from test_null; +----------+-------------+ | count(*) | count(name) | +----------+-------------+ | 2 | 1 | +----------+-------------+ 1 row in set (0.00 sec) //count(*) returns all rows ignore the null while count(name) returns the non-null rows in column "name". //This will also leads to uncertainty if someone is unaware of the details above. 如果使用者对NULL属性不熟悉,很容易统计出错误的结果. When using distinct,group by,order by,all null values are considered as the same value. (root@localhost mysql3306.sock)[zlm]>insert into test_null values(3,null); Query OK, 1 row affected (0.00 sec) (root@localhost mysql3306.sock)[zlm]>select distinct name from test_null; +------+ | name | +------+ | zlm | | NULL | +------+ 2 rows in set (0.00 sec) //Two rows of null value returned one and the result became two. (root@localhost mysql3306.sock)[zlm]>select name from test_null group by name; +------+ | name | +------+ | NULL | | zlm | +------+ 2 rows in set (0.00 sec) //Two rows of null value were put into the same group. //By default,group by will also sort the result(null row showed first). (root@localhost mysql3306.sock)[zlm]>select id,name from test_null order by name; +----+------+ | id | name | +----+------+ | 2 | NULL | | 3 | NULL | | 1 | zlm | +----+------+ 3 rows in set (0.00 sec) //Three rows were sorted(two null rows showed first). MySQL supports to use index on column which contains null value(what's different from oracle). (root@localhost mysql3306.sock)[sysbench]>show tables; +--------------------+ | Tables_in_sysbench | +--------------------+ | sbtest1 | | sbtest10 | | sbtest2 | | sbtest3 | | sbtest4 | | sbtest5 | | sbtest6 | | sbtest7 | | sbtest8 | | sbtest9 | +--------------------+ 10 rows in set (0.00 sec) (root@localhost mysql3306.sock)[sysbench]>show create table sbtest1\G *************************** 1. row *************************** Table: sbtest1 Create Table: CREATE TABLE `sbtest1` ( `id` int(11) NOT NULL AUTO_INCREMENT, `k` int(11) NOT NULL DEFAULT '0', `c` char(120) NOT NULL DEFAULT '', `pad` char(60) NOT NULL DEFAULT '', PRIMARY KEY (`id`), KEY `k_1` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=100001 DEFAULT CHARSET=utf8 1 row in set (0.00 sec) (root@localhost mysql3306.sock)[sysbench]>alter table sbtest1 modify k int null,modify c char(120) null,modify pad char(60) null; Query OK, 0 rows affected (4.14 sec) Records: 0 Duplicates: 0 Warnings: 0 (root@localhost mysql3306.sock)[sysbench]>insert into sbtest1 values(100001,null,null,null); Query OK, 1 row affected (0.00 sec) (root@localhost mysql3306.sock)[sysbench]>explain select id,k from sbtest1 where id=100001; +----+-------------+---------+------------+-------+---------------+---------+---------+-------+------+----------+-------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+---------+------------+-------+---------------+---------+---------+-------+------+----------+-------+ | 1 | SIMPLE | sbtest1 | NULL | const | PRIMARY | PRIMARY | 4 | const | 1 | 100.00 | NULL | +----+-------------+---------+------------+-------+---------------+---------+---------+-------+------+----------+-------+ 1 row in set, 1 warning (0.00 sec) (root@localhost mysql3306.sock)[sysbench]>explain select id,k from sbtest1 where k is null; +----+-------------+---------+------------+------+---------------+------+---------+-------+------+----------+--------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+---------+------------+------+---------------+------+---------+-------+------+----------+--------------------------+ | 1 | SIMPLE | sbtest1 | NULL | ref | k_1 | k_1 | 5 | const | 1 | 100.00 | Using where; Using index | +----+-------------+---------+------------+------+---------------+------+---------+-------+------+----------+--------------------------+ 1 row in set, 1 warning (0.00 sec) //In the first query,the newly added row is retrieved by primary key. //In the second query,the newly added row is retrieved by secondary key "k_1" //It has been proved that indexes can be used on the columns which contain null value. //column "k" is int datatype which occupies 4 bytes,but the value of "key_len" turn out to be 5.what's happed?Because null value needs 1 byte to store the null flag in the rows. 这个是我自己测试的例子. mysql> select * from test_1; +-----------+------+------+ | name | code | id | +-----------+------+------+ | gaoyi | wo | 1 | | gaoyi | w | 2 | | chuzhong | wo | 3 | | chuzhong | w | 4 | | xiaoxue | dd | 5 | | xiaoxue | dfdf | 6 | | sujianhui | su | 99 | | sujianhui | NULL | 99 | +-----------+------+------+ 8 rows in set (0.00 sec) mysql> explain select * from test_1 where code is NULL; +----+-------------+--------+------------+------+---------------+------------+---------+-------+------+----------+-----------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+--------+------------+------+---------------+------------+---------+-------+------+----------+-----------------------+ | 1 | SIMPLE | test_1 | NULL | ref | index_code | index_code | 161 | const | 1 | 100.00 | Using index condition | +----+-------------+--------+------------+------+---------------+------------+---------+-------+------+----------+-----------------------+ 1 row in set, 1 warning (0.00 sec) mysql> explain select * from test_1 where code is not NULL; +----+-------------+--------+------------+-------+---------------+------------+---------+------+------+----------+-----------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+--------+------------+-------+---------------+------------+---------+------+------+----------+-----------------------+ | 1 | SIMPLE | test_1 | NULL | range | index_code | index_code | 161 | NULL | 7 | 100.00 | Using index condition | +----+-------------+--------+------------+-------+---------------+------------+---------+------+------+----------+-----------------------+ 1 row in set, 1 warning (0.00 sec) mysql> explain select * from test_1 where code='dd'; +----+-------------+--------+------------+------+---------------+------------+---------+-------+------+----------+-----------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+--------+------------+------+---------------+------------+---------+-------+------+----------+-----------------------+ | 1 | SIMPLE | test_1 | NULL | ref | index_code | index_code | 161 | const | 1 | 100.00 | Using index condition | +----+-------------+--------+------------+------+---------------+------------+---------+-------+------+----------+-----------------------+ 1 row in set, 1 warning (0.00 sec) mysql> explain select * from test_1 where code like "dd%"; +----+-------------+--------+------------+-------+---------------+------------+---------+------+------+----------+-----------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+--------+------------+-------+---------------+------------+---------+------+------+----------+-----------------------+ | 1 | SIMPLE | test_1 | NULL | range | index_code | index_code | 161 | NULL | 1 | 100.00 | Using index condition | +----+-------------+--------+------------+-------+---------------+------------+---------+------+------+----------+-----------------------+ 1 row in set, 1 warning (0.00 sec) Summary 总结
|
请发表评论