【数据库】表字段设计时不推荐使用可空值(NULL)

news2024/9/21 10:42:42

【Mysql】数据库系列


文章目录

  • 前言
  • 一、表和数据准备
  • 二、验证
    • 1.NOT IN子查询在有NULL值的情况下返回永远为空结果
    • 2.使用!=去查询可空值字段时,数据中存在NULL,NULL记录查询不到
    • 3.如果在两个字段进行拼接:比如前缀+名字,字段为空会造成拼接的结果为NULL
    • 4.如果有 Null column 存在的情况下,count(Null column),null 值不会参与统计
    • 5. Null 字段的判断方式
    • 6.可空字段索引,会增加额外的空间
  • 总结


前言

在表设计字段时,不推荐使用可空值,推荐使用一个有意义的值去代替NULL,这样有利于代码的可读性和可维护性,并能从约束上增强业务数据的规范性。《高性能mysql》中给出的理由是:

Mysql难以优化引用可空列查询,它会使索引、索引统计和值更加复杂。可空列需要更多的存储空间,还需要mysql内部进行特殊处理。可空列被索引后,每条记录都需要一个额外的字节,还能导致MYisam 中固定大小的索引变成可变大小的索引。
下面举例子说明。


一、表和数据准备

创建表:student-01(name可以为NULL)、student-02(name不可以为NULL)
DDL:

-- `student-01` definition

CREATE TABLE `student-01` (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '主键id',
  `age` int DEFAULT '0' COMMENT '年龄',
  `name` varchar(50) DEFAULT NULL COMMENT '名字',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='学生表01';
-- `student-02` definition

CREATE TABLE `student-02` (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '主键id',
  `age` int DEFAULT '0' COMMENT '年龄',
  `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '名字',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='学生表';

数据:

INSERT INTO `student-01` (id, age, name) VALUES(1, 12, '小米1');
INSERT INTO `student-01` (id, age, name) VALUES(2, 23, '小rose1');
INSERT INTO `student-01` (id, age, name) VALUES(3, 12, '小jeck1');
INSERT INTO `student-01` (id, age, name) VALUES(4, 8, '小ming');
INSERT INTO `student-01` (id, age, name) VALUES(5, 11, '');
INSERT INTO `student-01` (id, age, name) VALUES(6, 46, 'NULL1');
INSERT INTO `student-01` (id, age, name) VALUES(7, 14, '小xu');
INSERT INTO `student-01` (id, age, name) VALUES(8, 11, NULL);
INSERT INTO `student-02` (id, age, name) VALUES(1, 12, '小米');
INSERT INTO `student-02` (id, age, name) VALUES(2, 23, '小rose');
INSERT INTO `student-02` (id, age, name) VALUES(3, 12, '小jeck');
INSERT INTO `student-02` (id, age, name) VALUES(4, 8, '');
INSERT INTO `student-02` (id, age, name) VALUES(5, 11, '');
INSERT INTO `student-02` (id, age, name) VALUES(6, 46, '小xiong');
INSERT INTO `student-02` (id, age, name) VALUES(7, 14, '小xu');

二、验证

1.NOT IN子查询在有NULL值的情况下返回永远为空结果

查询student-02中名字不存在student-01中的,推测的结果中应该有:小米、小rose、小jeck、小xiong,这几个只存在student-02。

select
	*
from
	`student-02` s
where
	s.name not in(
	select
		s2.name
	from
		`student-01` s2 )

运行结果:空,什么多没有。
在这里插入图片描述

2.使用!=去查询可空值字段时,数据中存在NULL,NULL记录查询不到

查询student-01中名字不等“小米1”的:

select * from `student-01` s where s.name  != '小米1'

输出结果:NULL值不包含在其中,id=8的记录没有包含进去。
在这里插入图片描述

3.如果在两个字段进行拼接:比如前缀+名字,字段为空会造成拼接的结果为NULL

将student-01表中name值加上“kexuexiong-”前缀:

select  s.id,CONCAT("kexuexiong-",s.name ) as name from `student-01` s

输出结果:
在这里插入图片描述

4.如果有 Null column 存在的情况下,count(Null column),null 值不会参与统计

统计名字有多少个:

select count(s.name ) from `student-01` s 

输出结果:
在这里插入图片描述

5. Null 字段的判断方式

使用!=NULL

select * from `student-01` s where s.name != null

输出结果;
在这里插入图片描述
使用=NULL

select * from `student-01` s where s.name = null

在这里插入图片描述
上面这两种方式是新手经常犯的错误,正确的方式应该是:
使用is not null

select * from `student-01` s where s.name is not null

使用is null

select * from `student-01` s where s.name is null

6.可空字段索引,会增加额外的空间

给student-01的name增加索引:

CREATE INDEX student_01_name_IDX USING BTREE ON `student-01` (name);

给student-02的name增加索引:

CREATE INDEX student_02_name_IDX USING BTREE ON `student-02` (name);

使用explain分析sql:

explain select * from `student-01` s where s.name = '小米1'
idselect_typetablepartitionstypepossible_keyskeykey_lenrefrowsfilteredExtra
1SIMPLEsrefstudent_01_name_IDXstudent_01_name_IDX203const1100.0
explain select * from `student-02` s where s.name = '小米'
idselect_typetablepartitionstypepossible_keyskeykey_lenrefrowsfilteredExtra
1SIMPLEsrefstudent_02_name_IDXstudent_02_name_IDX202const1100.0

两条查询语句都走name索引,但是key_len(索引字段的长度)不同。可空值得student-01(203)中比不可空值的student-02(202)多了1,两者类型都为varchar(50),编码集:utf8mb4。

key_len 的计算规则和三个因素有关:数据类型、字符编码、是否为 NULL

  • key_len 202 == 50*4(utf8 4字节) + 2 (存储 varchar 变长字符长度 2字节,定长字段无需额外的字节)

  • key_len 203== 20*4(utf8mb4 4字节) + 1 (是否为 Null 的标识) + 2 (存储 varchar 变长字符长度 2字节,定长字段无需额外的字节)


总结

综合以上的案列分析,不建议字段设计时使用可空值。推荐使用一个有意义的值去代替NULL,这样有利于代码的可读性和可维护性,并能从约束上增强业务数据的规范性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/902403.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Azure虚拟网络对等互连

什么是Azure虚拟网络对等互联 Azure虚拟网络对等互联(Azure Virtual Network peering)是一种连接两个虚拟网络的方法,使得这两个虚拟网络能够在同一地理区域内进行通信。它通过私有IP地址在虚拟网络之间建立网络连接,不论是在同一…

Java 项目日志实例:LogBack

点击下方关注我,然后右上角点击...“设为星标”,就能第一时间收到更新推送啦~~~ LogBack 和 Log4j 都是开源日记工具库,LogBack 是 Log4j 的改良版本,比 Log4j 拥有更多的特性,同时也带来很大性能提升。LogBack 官方建…

华为OD机试 - 全量和已占用字符集 - 数据结构map(Java 2022 Q4 100分)

目录 专栏导读一、题目描述二、输入描述三、输出描述四、解题思路五、Java算法源码六、效果展示1、输入2、输出 华为OD机试 2023B卷题库疯狂收录中,刷题点这里 专栏导读 本专栏收录于《华为OD机试(JAVA)真题(A卷B卷)》…

基于51单片机直流电机PWM调速液晶1602显示设计

一、系统方案 本文主要研究了利用MCS-51系列单片机控制PWM信号从而实现对直流电机转速进行控制的方法。本文中采用了三极管组成了PWM信号的驱动系统,并且对PWM信号的原理、产生方法以及如何通过软件编程对PWM信号占空比进行调节,从而控制其输入信号波形等…

Endnote在线链接pubmed的时候报错12057:不能连接到吊销服务器,或者未能获得最终响应?

​嘎嘎嘎问题如下: 解决办法: 打开控制面板: ok,完了之后再去EndNote就不会出现此问题了。(有的可能需要重启电脑,重启EndNote才会生效)

基于MOEA/D求解电力系统中环境经济调度问题(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

三维重建_基于图像的三维重建_面片/光度一致性

参考: 深蓝学院 基于图像的三维重建 1. 三维重建的流程回顾 基于深度图的三维重建:从无序图像获取稀疏点云和位姿,然后进行多视角立体重建。 多视角立体重建包含:(输入稀疏点云、各个图像位姿、图像)先进行立体对(3D-2D,2D-2D)的选择,然后计算深度图,接着进行深度图…

如何绕过计算机任何限制

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、创建记事本总结 前言 如果您在学校的电脑或笔记本就会发现它会限制您的天马行空的想法,因为它会限制command,powershell&#xff0…

java八股文面试[JVM]——JVM内存结构

参考: JVM学习笔记(一)_卷心菜不卷Iris的博客-CSDN博客 JVM是运行在操作系统之上的,它与硬件没有直接的交互 JVM内存结构: 方法区:存储已被虚拟机加载的类元数据信息(元空间) 堆:存放对象实…

【C语言】C语言用数组算平均数,并输出大于平均数的数

题目 让用户输入一系列的正整数&#xff0c;最后输入“-1”表示输入结束&#xff0c;然后程序计算出这些数的平均数&#xff0c;最后输出输入数字的个数和平均数以及大于平均数的数 代码 #include<stdio.h> int main() {int x;double sum 0;int cnt 0;int number[100…

SAP MM学习笔记26- SAP中 振替转记(转移过账)和 在库转送(库存转储)1- 移动Type间振替转记

SAP 中在库移动 不仅有入库&#xff08;GR&#xff09;&#xff0c;出库&#xff08;GI&#xff09;&#xff0c;也可以是单纯内部的转记或转送。 1&#xff0c;振替转记&#xff08;转移过账&#xff09; 2&#xff0c;在库转送&#xff08;库存转储&#xff09; 1&#xff…

Ae 效果:CC Scale Wipe、CC Radial ScaleWipe

过渡/CC Scale Wipe Transition/CC Scale Wipe CC Scale Wipe&#xff08;CC 缩放擦除&#xff09;主要通过缩放拉伸来擦除图层内容&#xff0c;从而实现一种独特的过渡效果。 CC Scale Wipe 效果示例 ◆ ◆ ◆ CC Scale Wipe 效果属性说明 Stretch 拉伸 控制对图层内容拉伸的…

中国剩余定理及扩展

目录 中国剩余定理解释 中国剩余定理扩展——求解模数不互质情况下的线性方程组&#xff1a; 代码实现&#xff1a; 互质&#xff1a; 非互质&#xff1a; 中国剩余定理解释 在《孙子算经》中有这样一个问题&#xff1a;“今有物不知其数&#xff0c;三三数之剩二&#x…

[三次握手]TCP三次握手由入门到精通(知识精讲)

⬜⬜⬜ &#x1f430;&#x1f7e7;&#x1f7e8;&#x1f7e9;&#x1f7e6;&#x1f7ea;(*^▽^*)欢迎光临 &#x1f7e7;&#x1f7e8;&#x1f7e9;&#x1f7e6;&#x1f7ea;&#x1f430;⬜⬜⬜ ✏️write in front✏️ &#x1f4dd;个人主页&#xff1a;陈丹宇jmu &am…

【Rust日报】2023-08-16 Neon 基于 rust 的 AWS Aurora Postgres 的无服务器开源替代品

Neon -- AWS Aurora Postgres 的无服务器开源替代品 简介 Neon 是 AWS Aurora Postgres 的无服务器开源替代品。它将存储和计算分开&#xff0c;并通过跨节点集群重新分布数据来替代 PostgreSQL 存储层。 尝试使用 Neon 免费套餐创建无服务器 Postgres 实例。然后使用您首选的 …

第二篇论文写作启发点V1

第二篇论文写作启发点V1 2.LLFLow模型的缺陷&#xff0c;这是先验&#xff0c;如果先验出现错误&#xff0c;那么后面这个模型都会错误。而我们使用了学习的方式去解决 3. 参考文献和实验时的对照模型最好使用最新的&#xff0c;就是没有被引用过的&#xff0c;这样可以降低论文…

12. Docker可视化工具

目录 1、前言 2、Docker UI 2.1、部署Docker UI 2.2、管理容器 3、Portainer 3.1、部署Portainer 3.2、管理容器 3.3、添加远程Docker 4、Shipyard 1、前言 Docker 提供了命令行工具来管理 Docker 的镜像和运行 Docker 的容器。我们也可以使用图形工具来管理 Docker。…

机器人远程控制软件设计

机器人远程控制软件设计 That’s all.

ECA模块的提出过程

接上文 作者首先肯定了通道注意力机制&#xff08;在 S E N e t SENet SENet当中提出来的&#xff09;的作用&#xff0c;对于没有参数的 S E − V A R 1 SE-VAR1 SE−VAR1模型&#xff0c;其效果仍然超过没有通道注意力机制的网络&#xff0c;可见注意力机制是有用的。 但是作…

CMC、mAP解析:图像检索领域评价指标

1. CMC&#xff1a; Cumulative Matching Characteristics 累计匹配特征 CMC是一种计算 top-n 的评价指标&#xff0c;主要用来评估闭集中rank-n的正确率。 下面举例说明&#xff1a; 在双模态特征匹配中。底库 Gallery 中有10条数据&#xff08;label分别为1&#xff0c;2&am…