mysql为什么建议创建字段的时候not null

相信大家在建表或者给表新加字段的时候,一些老司机们都会建议我们,字段要定义为not null,原因呢是一是占用存储空间,另一个是避免出现一些意料之外的错误。当然针对这个问题,大家可能也会在网上去搜下,不过网上一些文章有的说不清楚,有的不仅解释不清楚,另外可能会让大家产生新的疑问。

所以今天呢,我们根据文档试着来梳理下not null相关的问题,希望能通过本篇文章让大家对这个null有个更进一步的认识,然后在平时的工作中不用再过多的纠结这个问题。

1. 列允许为null时的存储问题?

要搞清楚这个问题,其实就要了解MySQL表的存储行(row format)格式,当然我们只说InnoDB存储引擎这块。表的存储行格式决定了MySQL的行的物理存储方式,进而会影响查询和DML操作的性能。

MySQL当前版本8.0目前包含这四种格式:REDUNDANT,COMPACT,DYNAMIC,和COMPRESSED;而当前MySQL默认的格式是DYNAMIC;

查看表的存储行格式row_format:SHOW TABLE STATUS LIKE 'test' (test就是要查询的表名);

因为DYNAMIC有关null的存储和COMPACT是一致的,所以我们直接以COMPACT为例。这里根据官网文档及《Mysql技术内幕-InnoDB存储引擎》,简单画了一下COMPACT格式的存储方式:

当然这里,还会包含一个6字节的事务ID字段和一个7字节的回滚指针字段,另外如果没有为表定义主键,则还会包含一个6字节的row ID字段,这里不是我们本文的重点,这里就不多说了。

  • 根据文档,如果行中列为空,则会在null占位这里占用一位(1 bit),如果行中有两个列为null,则这里会占用两位,以此类推,然后存储的时候,不满8个bit,算1个字节;
  • 也就是说如果有1~8个null,那么会占用1个字节,9~16个null,会占用2个字节,如果为null的列的数量是N,那么最终需要的字节数是:CEILING(N/8)。
  • 另外,null除了在该位置处会占用空间外,其他不占用空间。官网来源:

The variable-length part of the record header contains a bit vector for indicatingNULLcolumns. If the number of columns in the index that can beNULLisN, the bit vector occupiesCEILING(N/8)bytes. (For example, if there are anywhere from 9 to 16 columns that can beNULL, the bit vector uses two bytes.) Columns that areNULLdo not occupy space other than the bit in this vector.

其实,到这里大家应该对null的占用空间问题清楚了吧 。接下来我们来梳理下null的一些特殊处理场景,这些场景才是我们值得注意的。

2. Mysql针对null的一些特殊逻辑处理

2.1 比较问题

如果查询字段是否为null,需要使用is null;如果要查询不为某个特定值(该值可能为null),如果使用!=,返回结果将不包含为null的数据。

比如想查询test表中 id不为1的记录,我们使用:

select * from demo where abc != 1;

那么查询等同于:

select * from demo where abc != 1 and abc is not null;

2.2 null不能用于范围查询,不能与非null进行比较

这块可以直接看官网的截图:

2.3 null与count

COUNT(column):统计结果不包含为null的行;COUNT(*) :对所有行进行统计,不管是否包含null,类似count(1);当然不仅仅是count方法,min,sum方法都是类似的:

mysql> SELECT COUNT(*), COUNT(age) FROM person; // output:3,2

这里参考自官网:MySQL :: MySQL 5.7 Reference Manual :: B.3.4.3 Problems with NULL Values

2.4 null与order by/group by

根据Mysql文档,order by中,如果使用asc进行排序,那么null值会排在最前面;desc的话,null会排在最后面;

For sorting with ORDER BY, NULL values sort before other values for ascending sorts, after other values for descending sorts.

而group by的话,所有为null的都是相同的,所以group by的时候会为一行;还有DISTINCT操作是一样的;

这里来源:MySQL :: MySQL 5.7 Reference Manual :: 9.1.7 NULL Values

2.5 null与索引

MYSQL 走索引的方式,目前只有 is NULL的情况下会走索引,当前如果联合索引中的查询符合条件也是生效的:

MySQL can perform the same optimization on col_name IS NULL that it can use for col_name = constant_value. For example, MySQL can use indexes and ranges to search for NULL with IS NULL.

来源:MySQL :: MySQL 5.7 Reference Manual :: 8.2.1.13 IS NULL Optimization

当null列被索引的时候,除了正常的数据类型占用的空间,需要额外占用一个字节的存储空间,这点我们一般可以通过执行计划看一下key_en的值,另外这里参考:

Due to the key storage format, the key length is one greater for a column that can beNULLthan for aNOT NULLcolumn.

3. 总结

根据MySQL的官网文档及《mysql技术内幕-存储引擎》和《高性能Mysql》一说,MySQL中存储null的确为额外占用一些空间,但将这些列从null优化为not null,并非会有很大的性能提升。

null的问题主要还是一些逻辑方面的问题,比如可能会使计算复杂些,会让我们处理的时候要多考虑些,亦或者是和其他中间件进行结合的时候,其他中间件对null的处理不太友好而出现一些问题等。

另外再说一点,建议大家多去看下MySQL官网的文档,另外如果英文不太好的小伙伴,可以使用Chrome浏览器的翻译功能,从我个人的体验来说,这个翻译功能还是很不错的。

其他:

为什么开发规范中不推荐NULL?
开发规范中不推荐使用NULL,并且倾向于使用NOT NULL约束,这样做有几个好处:

数据完整性:使用NOT NULL可以确保列中始终有值,这有助于维护数据的完整性和一致性。
避免歧义:NULL在SQL中是一个特殊的值,表示“未知”或“不存在”。它不同于空字符串或0,而且在进行比较和计算时,NULL会导致一些意想不到的结果。避免使用NULL可以减少这种歧义。
性能优化:不使用NULL可以简化数据库的内部处理。例如,您提到的NULL值列表就是InnoDB为了跟踪哪些列包含NULL值而维护的额外数据结构。如果表中的所有列都不允许NULL值,那么InnoDB就不需要维护这个列表,从而节省了空间并可能提高性能。
关于NULL值列表的处理过程简要概括一下:

InnoDB首先会确定哪些列允许存储NULL值。这包括那些没有明确设置为NOT NULL的列。
对于允许NULL值的列,InnoDB会为它们分配一个二进制位,这些位组合在一起形成了NULL值列表。这个列表用于跟踪每一行中哪些列的值是NULL。
二进制位的排列是逆序的,这意味着表中的第一列(如果它允许NULL值)将对应于列表中的最后一个二进制位,而最后一列将对应于第一个二进制位。
当二进制位的值为1时,表示对应的列值为NULL;当值为0时,表示对应的列值不为NULL。
通过这种方式,InnoDB能够高效地存储和检索NULL值信息,尽管这会增加一些额外的存储开销。但是,如果表中的所有列都设置为NOT NULL,那么这个NULL值列表就完全不需要了,从而节省了这部分空间。这也是为什么开发规范中经常推荐尽量避免使用NULL的原因之一。

mysql隐藏列?

每行数据除了用户定义的列之外,还包含两个隐藏列:6字节的事务ID列和7字节的回滚指针列。
对于NULL值,它只占用NULL标志位,不占用额外的存储空间。
此外,如果表没有定义主键,InnoDB还会为每行添加一个6字节的rowid列。这些隐藏列和rowid列对于保证事务的ACID特性和数据的恢复至关重要。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

制作炫酷个人网页:用 HTML 和 CSS3 展现你的风格

你是否觉得自己的网站应该看起来更炫酷?今天我将教你如何使用 HTML 和 CSS3 制作一个拥有炫酷动画和现代设计风格的个人网页,让它在任何设备上看起来都无敌酷炫! 哈哈哈哈哈哈哈哈,我感觉自己有点中二哈哈哈哈~ 目录 炫酷设计理念构建 HTML …

【电力系统】基于遗传算法的33节点电力系统无功优化及MATLAB实现

摘要 本文研究了基于遗传算法的33节点配电系统的无功优化问题。通过调整电容器的安装位置和容量,以最小化系统的无功损耗和电压偏差。研究使用遗传算法对无功优化问题进行求解,并在MATLAB环境中进行仿真实现。实验结果表明,该方法能够有效地…

零工市场小程序:推动零工市场建设

人力资源和社会保障部在2024年4月发布了标题为《地方推进零工市场建设经验做法》的文章。 零工市场小程序的功能 信息登记与发布 精准匹配、推送 在线沟通 权益保障 零工市场小程序作为一个找零工的渠道,在往后随着技术的发展和政策的支持下,功能必然…

★ C++进阶篇 ★ 二叉搜索树

Ciallo&#xff5e;(∠・ω< )⌒☆ ~ 今天&#xff0c;我将继续和大家一起学习C进阶篇第三章----二叉搜索树 ~ ❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️ 澄岚主页&#xff1a;椎名澄嵐-CSDN博客 C基础篇专栏&#xff1a;★ C基础篇 ★_椎名澄嵐的博客-CSD…

【matlab】生成 GIF 的函数(已封装可直接调用)

文章目录 前言一、函数输入与输出二、函数代码三、例程&#xff08;可直接运行&#xff09;参考文献 前言 生成 gif 图片时遇到的问题&#xff0c;为了后续调用方便&#xff0c;封装为函数 一、函数输入与输出 输入&#xff1a; cell_figure: cell 数组&#xff0c;数组元素是…

git 更换远程地址的方法

需要将正在开发的代码远程地址改成新的地址&#xff0c;通过查询发现有三个方法可以实现&#xff0c;特此记录。具体方法如下&#xff1a; &#xff08;1&#xff09;通过命令直接修改远程仓库地址 git remote 查看所有远程仓库git remote xxx 查看指定远程仓库地址git remote…

ProtoBuf序列化框架介绍

文章目录 ProtoBuf介绍使用流程 QUICK START创建.proto文件注释语法编译部分代码展示使用接口运行结果 ProtoBuf介绍 ProtoBuf全称是Protocol Buffer&#xff0c;是一个数据结构的序列化和反序列化框架 他又很多好处&#xff0c;首先是他支持跨平台&#xff0c;支持Java、C、…

Mac 上,终端如何开启 proxy

文章目录 为什么要这么做前提步骤查看 port查看代理的port配置 bash测试 为什么要这么做 mac 上的终端比较孤僻吧&#xff0c;虽然开了&#xff0c;但是终端并不走&#x1fa9c;…产生的现象就是&#xff0c;浏览器可以访问&#x1f30d;&#xff0c;但是终端不可以访问&#…

创建Application(Qt)模板项目时的 Base class选择

在Qt中&#xff0c;当你使用Qt Creator新建一个Qt Widgets Application项目时&#xff0c;选择Base class是一个重要的步骤&#xff0c;因为它决定了你的主窗口或对话框将继承自哪个类&#xff0c;从而决定了你的应用程序将具有哪些基本的功能和外观。以下是一些常见的Base cla…

docker进入容器运行命令

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

3D生成技术再创新高:VAST发布Tripo 2.0,提升AI 3D生成新高度

随着《黑神话悟空》的爆火&#xff0c;3D游戏背后的AI 3D生成技术也逐渐受到更多的关注。虽然3D大模型的热度相较于语言模型和视频生成技术稍逊一筹&#xff0c;但全球的3D大模型玩家们却从未放慢脚步。无论是a16z支持的Yellow&#xff0c;还是李飞飞创立的World Labs&#xff…

双击就可以打开vue项目,而不用npm run dev

右键点击桌面或其他位置&#xff0c;选择“新建” -> “快捷方式”&#xff0c;在“对象的位置”处直接输入“npm run dev”&#xff0c;然后下一步 自定义一个快捷方式名称 完成后&#xff0c;桌面会创建一个快捷方式&#xff0c;右键快捷方式选择属性&#xff0c;可以看…

为什么 ECB 模式不安全

我们先来简单了解下 ECB 模式是如何工作的 ECB 模式不涉及链接模式&#xff0c;所以也就用不着初始化向量&#xff0c;那么相同的明文分组就会被加密成相同的密文分组&#xff0c;而且每个分组运算都是独立的&#xff0c;这也就意味着可以并行提高运算效率&#xff0c;但也正是…

prometheus通过nginx-vts-exporter监控nginx

Prometheus监控nginx有两种方式。 一种是通过nginx-exporter监控&#xff0c;需要开启nginx_stub_status,主要是nginx自身的status信息&#xff0c;metrics数据相对较少&#xff1b; 另一种是使用nginx-vts-exporter监控&#xff0c;但是需要在编译nginx的时候添加nginx-module…

Shader 中的光源

1、Shader 开发中常用的光源属性 Unity当中一共支持四种光源类型&#xff1a; 平行光&#xff08;Directional&#xff09;点光源&#xff08;Point&#xff09;聚光灯&#xff08;Spot&#xff09;面光源&#xff08;Area&#xff09;— 面光源仅在烘焙时有用 不管光源类型到…

Docker 华为云镜像加速器配置

​​ 操作说明 1. 安装/升级容器引擎客户端 推荐安装1.11.2以上版本的容器引擎客户端 2. 加速器地址 访问华为云容器镜像服务&#xff1a;https://console.huaweicloud.com/swr/ 获取加速器地址 https://xxxxxxxxx.mirror.swr.myhuaweicloud.com3. 配置镜像加速器 针对…

【Qt | QLineEdit】Qt 中使 QLineEdit 响应 鼠标单击、双击事件 的两个方法

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; ⏰发布时间⏰&#xff1a; 2024-09-14 …

Flutter-底部选择弹窗(showModalBottomSheet)

前言 现在有个需求&#xff0c;需要用底部弹窗来添加定时的重复。在这里使用原生的showModalBottomSheet来实现 showModalBottomSheet的Props 名称 描述 isScrollControlled全屏还是半屏isDismissible外部是否可以点击&#xff0c;false不可以点击&#xff0c;true可以点击&a…

STM32 移植FATFS时遇到ff_oem2uni函数未定义问题

STM32 移植FATFS时遇到ff_oem2uni/ff_uni2oem/ff_wtoupper函数未定义问题 在移植STM32 FATFS文件系统代码时&#xff0c;完成后编译遇到如下错误&#xff1a; 经过排查分析&#xff0c;是文件没有添加完全导致的&#xff1a; 把ffunicode.c文件添加进工程就可以了&#xff…

01-Mac OS系统如何下载安装Python解释器

目录 Mac安装Python的教程 mac下载并安装python解释器 如何下载和安装最新的python解释器 访问python.org&#xff08;受国内网速的影响&#xff0c;访问速度会比较慢&#xff0c;不过也可以去我博客的资源下载&#xff09; 打开历史发布版本页面 进入下载页 鼠标拖到页面…