数据库允许空值(null),往往是悲剧的开始(1分钟系列)

探讨数据库中允许字段为空可能引发的问题,包括全表扫描、不符合预期的查询结果及优化策略,强调合理使用索引和避免空值的重要性。

数据库字段允许空值,会遇到一些问题,此处包含的一些知识点,和大家聊一聊。

 

数据准备:

create table user (

id int,

name varchar(20),

index(id)

)engine=innodb;

 

insert into user values(1,'shenjian');

insert into user values(2,'zhangsan');

insert into user values(3,'lisi');

 

说明:

id为索引,非唯一(non unique),允许空(null)。

 

知识点1(热身):负向查询不能命中索引,会导致全表扫描。

explain select * from user where id!=1;

索引字段id上的不等于查询,如上图所示:

(1)type=ALL,全表扫描;

(2)rows=3,全表只有3行;

 

知识点2(划重点):允许空值,不等于(!=)查询,可能导致不符合预期的结果。

insert into user(name) values('wangwu');

先构造一条id为NULL的数据,可以看到共有4条记录。

 

select * from user where id!=1;

再次执行不等于查询。

你猜结果集有几条记录(共4条,不等于排除1条)?

答错了!

结果集只有2条记录,空值记录记录并未出现在结果集里。

select * from user where id!=1 or id is null;

如果想到得到符合预期的结果集,必须加上一个or条件。

画外音:恶心不恶心,这个大坑你踩过没有?

 

知识点3(附加):某些or条件,又可能导致全表扫描,此时应该优化为union。

explain select * from user where id=1;

索引字段id上的等值查询,命中索引,如上图所示:

(1)type=ref,走非唯一索引;

(2)rows=1,预估扫描1行;

 

explain select * from user where id is null;

索引字段id上的null查询,也命中索引,如上图所示:

(1)type=ref,走非唯一索引;

(2)rows=1,预估扫描1行;

 

explain select * from user where id=1 or id is null;

如果放到一个SQL语句里用or查询,则会全表扫描,如上图所示:

(1)type=ALL,全表扫描;

(2)rows=4,全表只有4行;

 

explain select * from user where id=1 

union

select * from user where id is null;

此时应该优化为union查询,又能够命中索引了,如上图所示:

(1)type=ref,走非唯一索引;

(2)rows=1,预估扫描1行;

画外音:第三行临时表的ALL,是两次结果集的合并。

 

总结

(1)负向比较(例如:!=)会引发全表扫描

(2)如果允许空值,不等于(!=)的查询,不会将空值行(row)包含进来,此时的结果集往往是不符合预期的,此时往往要加上一个or条件,把空值(is null)结果包含进来;

(3)or可能会导致全表扫描,此时可以优化为union查询;

(4)建表时加上默认(default)值,这样能避免空值的坑;

(5)explain工具是一个好东西;

 

希望大家有收获!

画外音:本文测试于MySQL5.6。

架构师之路-分享技术思路

相关推荐:

缓冲池(buffer pool),这次彻底懂了!!!

写缓冲(change buffer),这次彻底懂了!!!

两类非常隐蔽的全表扫描 | 1分钟系列

MyISAM与InnoDB的索引差异 | 1分钟系列

<think>嗯,用户的问题是关于数据库表中允许空值是否属于约束的定义或规则。我需要先确认用户的问题核心。他们可能在学习数据库设计时遇到了关于空值和约束的关系,想明确空值是否属于约束的一种。 首先,我应该回顾数据库约束的基本概念。根据引用[1]和引用[2],约束用于强制数据完整性和一致性。常见的约束类型包括非空约束、主键、外键等。引用[1]提到非空约束属于约束的一种,而允许空值可能与之相反,即没有非空约束的情况下字段允许空值,但这是否算作约束呢? 根据引用[2],非空约束(NOT NULL)明确属于约束的一种,用于确保字段不为空。而允许空值可能意味着该字段没有应用非空约束,但用户的问题在于,允许空值本身是否被定义为某种约束。在标准数据库术语中,允许空值是默认行为,不需要特别声明,因此可能不被视为约束。约束通常是限制性的,如必须满足某些条件,而允许空值则是缺少这种限制。 引用[3]中的例子,创建表时指定了主键约束,但没有提到非空约束的其他字段,这些字段默认允许空值。这说明默认情况下字段允许空值,除非显式添加非空约束。因此,允许空值本身并不是约束,而是没有应用非空约束的结果。 需要确认是否有其他约束类型涉及允许空值。例如,唯一约束允许空值,但主键不允许。这可能让用户混淆,但根据引用[2],唯一约束允许空值,但主键约束不允许。因此,允许空值属于字段的默认状态,而非约束定义的一部分。 总结:允许空值不属于约束,而是字段的默认属性。约束如非空约束用于限制不允许空值,而允许空值不需要约束定义。因此,用户的问题答案是否定的,允许空值不属于约束,而是约束的缺失。</think>### 数据库表中允许空值的约束属性分析 #### 1. 允许空值的本质属性 允许空值NULL)是字段的**默认属性**,不需要通过约束定义即可存在。当字段未明确声明`NOT NULL`约束时,默认允许存储空值[^1][^2]。 #### 2. 非空约束的明确规则 若需**禁止空值**,必须显式添加`NOT NULL`约束。例如: ```sql CREATE TABLE users ( id INT PRIMARY KEY, username VARCHAR(50) NOT NULL -- 禁止空值 ); ``` 此时`username`字段若插入空值会触发约束违规[^1][^3]。 #### 3. 约束与空值的逻辑关系 - **属于约束的情况**:`NOT NULL`是明确的约束类型,属于空值约束(Nullability Constraint)[^2]。 - **不属于约束的情况**:允许空值是字段的默认状态,无需通过约束实现。例如未声明`NOT NULL`的字段天然允许空值[^1][^3]。 #### 4. 与其他约束的关联性 - **主键约束**:隐含`NOT NULL`属性(主键字段禁止空值)[^2]。 - **唯一约束**:允许空值(除非同时声明`NOT NULL`)[^2]。 - **外键约束**:允许外键字段为空,除非显式限制[^4]。 #### 总结 允许空值本身**不属于约束定义**,而是字段的默认行为。约束的作用是**限制空值**而非允许空值
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值