Chinaunix首页 | 论坛 | 博客
  • 博客访问: 7610404
  • 博文数量: 368
  • 博客积分: 9600
  • 博客等级: 上校
  • 技术积分: 18875
  • 用 户 组: 普通用户
  • 注册时间: 2009-01-01 00:00
文章分类

全部博文(368)

文章存档

2017年(9)

2016年(19)

2015年(3)

2014年(6)

2013年(8)

2012年(78)

2011年(66)

2010年(135)

2009年(44)

分类: LINUX

2012-03-29 18:43:56


一直听说设计数据库的时候尽可能设置成NOT NULL,那么到底设置成NULL和NOT NULL有什么区别呢?
今天刚好有时间就探究一下:
主要测试的内容有:
1、测试NULL对索引的影响
2、测试NULL对组合索引的影响
3、测试NULL对磁盘空间的影响

测试环境为:
系统环境:Centos 5.5 64 bit
软件环境:MYSQL 5.1.50

表结构为:
CREATE TABLE `zhang` (
  `id` int(11) NOT NULL DEFAULT '0',
  `name` varchar(20) DEFAULT NULL,
  `address` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_name_address` (`name`,`address`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

插入数据的存储过程为:
DROP PROCEDURE IF EXISTS add_data ;
DELIMITER //
CREATE PROCEDURE add_data (IN c_count INT,OUT result INT,OUT starttime DATETIME,OUT endtime DATETIME)
BEGIN
DECLARE c_name VARCHAR(20) DEFAULT 'zhang';
DECLARE c_address VARCHAR(20) DEFAULT 'jiangxi';
SELECT NOW() INTO starttime;
WHILE c_count <= 100000 DO
INSERT INTO zhang (id,`name`,`address`) VALUES(c_count,CONCAT(c_name,c_count),CONCAT(c_address,c_count));
SET c_count=c_count+1;
END WHILE;
SELECT NOW() INTO endtime;
SELECT MAX(id) INTO result FROM zhang;
END
//

调用存储过程插入数据:
CALL add_data(1,@result,@starttime,@endtime);

测死NULL对单个索引的影响:
NULL值很少的情况
ALTER TABLE zhang DROP INDEX idx_name_address,ADD INDEX (`name`);
UPDATE zhang SET `name`=NULL WHERE `name`='zhang99991' ;
EXPLAIN SELECT * FROM zhang WHERE `name`  IS NULL;
+----+-------------+-------+------+---------------+------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref   | rows | Extra       |
+----+-------------+-------+------+---------------+------+---------+-------+------+-------------+
|  1 | SIMPLE      | zhang | ref  | name          | name | 63      | const |    1 | Using where |
+----+-------------+-------+------+---------------+------+---------+-------+------+-------------+
可以用到索引
EXPLAIN SELECT * FROM zhang WHERE `name`  IS NOT NULL;
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows   | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
|  1 | SIMPLE      | zhang | ALL  | name          | NULL | NULL    | NULL | 100216 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
用不到索引
接下来看看含有很多NULL值的情况:
UPDATE zhang SET `name`=NULL LIMIT 60000 ;
EXPLAIN SELECT * FROM zhang WHERE `name` IS NULL;
+----+-------------+-------+------+---------------+------+---------+-------+-------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref   | rows  | Extra       |
+----+-------------+-------+------+---------------+------+---------+-------+-------+-------------+
|  1 | SIMPLE      | zhang | ref  | name          | name | 63      | const | 52420 | Using where |
+----+-------------+-------+------+---------------+------+---------+-------+-------+-------------+
能用到索引
EXPLAIN SELECT * FROM zhang WHERE `name` IS NOT NULL;
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows   | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
|  1 | SIMPLE      | zhang | ALL  | name          | NULL | NULL    | NULL | 104841 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
不能用到索引


测试NULL对组合索引的影响:
UPDATE zhang SET `address`=NULL WHERE `name`='zhang99991' AND address='jiangxi99991';
EXPLAIN SELECT * FROM zhang WHERE `name`='zhang99991' AND `address` IS NULL;
+----+-------------+-------+------+------------------+------------------+---------+-------------+------+--------------------------+
| id | select_type | table | type | possible_keys    | key              | key_len | ref         | rows | Extra                    |
+----+-------------+-------+------+------------------+------------------+---------+-------------+------+--------------------------+
|  1 | SIMPLE      | zhang | ref  | idx_name_address | idx_name_address | 126     | const,const |    1 | Using where; Using index |
+----+-------------+-------+------+------------------+------------------+---------+-------------+------+--------------------------+
可以是用到索引
UPDATE zhang SET `name`=NULL WHERE `name`='zhang99992' AND address='jiangxi99992';
EXPLAIN SELECT * FROM zhang WHERE `name` IS NULL AND address='jiangxi99992';
+----+-------------+-------+------+------------------+------------------+---------+-------------+------+--------------------------+
| id | select_type | table | type | possible_keys    | key              | key_len | ref         | rows | Extra                    |
+----+-------------+-------+------+------------------+------------------+---------+-------------+------+--------------------------+
|  1 | SIMPLE      | zhang | ref  | idx_name_address | idx_name_address | 126     | const,const |    1 | Using where; Using index |
+----+-------------+-------+------+------------------+------------------+---------+-------------+------+--------------------------+
还是能用到索引
EXPLAIN SELECT * FROM zhang WHERE `name` IS NULL;
+----+-------------+-------+------+------------------+------------------+---------+-------+------+--------------------------+
| id | select_type | table | type | possible_keys    | key              | key_len | ref   | rows | Extra                    |
+----+-------------+-------+------+------------------+------------------+---------+-------+------+--------------------------+
|  1 | SIMPLE      | zhang | ref  | idx_name_address | idx_name_address | 63      | const |    1 | Using where; Using index |
+----+-------------+-------+------+------------------+------------------+---------+-------+------+--------------------------+
还是能用到索引
UPDATE zhang SET address=NULL WHERE `name` IS NULL;
EXPLAIN SELECT * FROM zhang WHERE `name` IS NULL AND address IS NULL;
+----+-------------+-------+------+------------------+------------------+---------+-------------+------+--------------------------+
| id | select_type | table | type | possible_keys    | key              | key_len | ref         | rows | Extra                    |
+----+-------------+-------+------+------------------+------------------+---------+-------------+------+--------------------------+
|  1 | SIMPLE      | zhang | ref  | idx_name_address | idx_name_address | 126     | const,const |    1 | Using where; Using index |
+----+-------------+-------+------+------------------+------------------+---------+-------------+------+--------------------------+
还是能用到索引
再看一下join查询,没有NULL的使用索引情况
EXPLAIN SELECT * FROM zhang a INNER JOIN zhang2 b ON  a.`name`=b.`name`;        
+----+-------------+-------+------+------------------+------------------+---------+--------------+--------+--------------------------+
| id | select_type | table | type | possible_keys    | key              | key_len | ref          | rows   | Extra                    |
+----+-------------+-------+------+------------------+------------------+---------+--------------+--------+--------------------------+
|  1 | SIMPLE      | a     | ALL  | name             | NULL             | NULL    | NULL         | 100420 |                          |
|  1 | SIMPLE      | b     | ref  | idx_name_address | idx_name_address | 63      | zhang.a.name |      1 | Using where; Using index |
+----+-------------+-------+------+------------------+------------------+---------+--------------+--------+--------------------------+
添加NULL值以后对索引的使用情况
UPDATE zhang SET `name`=NULL LIMIT 50000;
UPDATE zhang2 SET `name`=NULL LIMIT 60000;
EXPLAIN SELECT * FROM zhang a INNER JOIN zhang2 b ON  a.`name`=b.`name`;
+----+-------------+-------+------+------------------+------------------+---------+--------------+-------+--------------------------+
| id | select_type | table | type | possible_keys    | key              | key_len | ref          | rows  | Extra                    |
+----+-------------+-------+------+------------------+------------------+---------+--------------+-------+--------------------------+
|  1 | SIMPLE      | a     | ALL  | name             | NULL             | NULL    | NULL         | 99844 |                          |
|  1 | SIMPLE      | b     | ref  | idx_name_address | idx_name_address | 63      | zhang.a.name |     1 | Using where; Using index |
+----+-------------+-------+------+------------------+------------------+---------+--------------+-------+--------------------------+


通过分别对单个索引和组合索引的测试得出结论NULL对组合索引没有什么太大影响

测试NULL对磁盘空间的影响:
没有NULL的情况
-rw-rw---- 1 mysql mysql 16777216 Mar 28 18:28 zhang.ibd
UPDATE zhang SET address=NULL LIMIT 50000;
将address列一半的值更改成NULL以后,占用磁盘空间的情况
-rw-rw---- 1 mysql mysql 18874368 Mar 28 18:31 zhang.ibd
发现占用的磁盘空间增长了不少。得出结论NULL
去掉索引再测试
UPDATE zhang SET address='jiangxi2' WHERE address IS NULL;
ALTER TABLE zhang DROP INDEX idx_name_address;
-rw-rw---- 1 mysql mysql 12582912 Mar 28 18:33 zhang.ibd
UPDATE zhang SET address=NULL LIMIT 50000;再查看磁盘空间的使用情况:
-rw-rw---- 1 mysql mysql 12582912 Mar 28 18:33 zhang.ibd
发现磁盘空间没有变化,因此综合两个测试可以得出结论:对NULL列加索引需要额外的磁盘空间,如果不是索引列就对磁盘空间没有影响

阅读(3754) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~