DBA:字段一定要设置为非空,省空间!我:你拉倒吧

背景

DBA 又把建表语句打回来了,原因是字段可空了!理由是为了省空间!!!!

语句如下:

CREATE TABLE user_info (

id bigint unsigned NOT NULL AUTO_INCREMENT,

user_id int NOT NULL COMMENT '用户id',

user_name varchar(64) NOT NULL COMMENT '真实姓名',

email varchar(30) NOT NULL COMMENT '用户邮箱',

nick_name varchar(45) COMMENT '昵称',

status tinyint NOT NULL COMMENT '用户状态,1-正常,2-注销,3-冻结',

address varchar(128) COMMENT '家庭住址',

--省略了一些属性,篇幅原因,这里删掉了

PRIMARY KEY (id),

KEY idx_user_id (user_id)

) ENGINE=InnoDB COMMENT='用户基本信息';

用户可能就是没有昵称啊,设置为可空,看起来也没啥问题啊!有没有一种被针对的感觉

其实你如果知道每条记录真正的存储格式,你就知道怎么怼他了。

正文

InnoDB 页的概念

Page 是 Innodb 存储的最基本结构,也是 Innodb 磁盘管理的最小单位,与数据库相关的所有内容都存储在 Page 结构里。

MySQL 的客户端和服务端的交互最小单位也是 Innodb 页(默认大小为 16K),也就是说如果你即使只查询一条记录,一次至少从磁盘上读取 16K 的内容到内存中。

Innodb 行格式

我们平时往数据库插入一条条的记录,这些记录在磁盘上存放格式也是以行记录的方式的。

Innodb 存储引擎目前有四种格式--COMPACT、REDUNDANT、DYNAMIC、COMPRESSED

从 MySQL5.7 开始,默认是 DYNAMIC 方式,我们用图片来看一下 Innodb 行格式大概示意图。(这里以 COMPACT为例,因为这 2 者基本上是一样的,只有一些细微的差别)

记录额外信息

这里只讲变长属性长度列表、NULL 值列表 2 个部分

1、变长属性长度列表

常见的关系型数据库都支持变长属性,比如上面的语句username varchar(64)中,64 是代表可存储的最大字符数,如果某条记录的名字是“张三”,会有什么样的问题呢

我们要让 MySQL 服务器知道每条记录的每个变长属性知道实际长度是多少,不然它会懵

我们来举一个栗子:


上面的记录 user_name,email,nick_name,address 都是 varchar 类型的,那么他存储的记录格式是什么样的呢

上图中的 09、0b、06、09 分别对应 user_name,email,nick_name、address 对应字节长度,16 进制(实际上无空格,这里只是为了方便看)。

至于为什么是倒序放的,不是本文重点,这里先不做解答

小彩蛋:varchar(M)中的 M 代表能存储的最大字符数,实际存储时都是按照字节来计算的,所以一个字段占用的实际字节数的公式:

RL(存储属性最多的字节数)=M(最多字符数)* W(当前字符集下最多需要几个字节表示一个字符)

所以在编码是 utf8mb4 的情况下,user_name 最多占用的字节数=64 * 4 = 256,所以该属性需要 2 个字节表示长度

为什么不是 1 个字节,1 个字节不正好是 256 吗?因为第一位是标记位,如果第一位是 0,表示用 1 个字节就可以表示该属性的长度,如果第一位是 1,表示需要用 2 个字节表示该属性的长度。

但是如果RL大于256,占用的字节也是2个,字段属性值保存一部分或者(数据地址)

如果另一条记录是这样的:


则对应的行格式如下:

昵称、家庭住址为空,则不在变长长度列表中出现。

2、NULL 值列表

我们在插入一条记录时,Innodb 引擎怎么处理

先统计允许为 NULL 的列有哪些

如果建表语句中,没有可空的字段,就没有 NULL 值列表;如果有可空的字段,那么每个可空字段对应一个二进制位,1-代表 NULL,0-不为 NULL

最小单位需要用字节来表示 NULL 值列表,如果只有 2 个可空值,至少也需要 1 个字节来表示,高位补 0,如张无忌对应的 NULL 值列表为 00000011,张三丰对应的 NULL 值列表为 00000000

张三丰对应的记录行格式(00000000):

张无忌对应的记录行格式(00000011):

综上

如果一张表没有可空的字段,比如建表语句如下:

语句如下:

CREATE TABLE user_info (

id bigint unsigned NOT NULL AUTO_INCREMENT,

user_id int NOT NULL COMMENT '用户id',

user_name varchar(64) NOT NULL COMMENT '真实姓名',

email varchar(30) NOT NULL COMMENT '用户邮箱',

nick_name varchar(45) NOT NULL COMMENT '昵称',

status tinyint NOT NULL COMMENT '用户状态,1-正常,2-注销,3-冻结',

address varchar(128) NOT NULL COMMENT '家庭住址',

--省略了一些属性,篇幅原因,这里删掉了

PRIMARY KEY (id),

KEY idx_user_id (user_id)

) ENGINE=InnoDB COMMENT='用户基本信息';

对应的行结构如下:

没有 NULL 值列表哪一项,但是虽然 NULL 列表中没有了,变长列表中会有,同时真实数据部分也会有,占用的空间更大,可见为了省空间这种说法站不住脚。

总结

原因到底是为什么呢?

MySQL 官方有那么一句话:

NULL columns require additional space in the rowto record whether their values are NULL. For MyISAM tables, each NULL columntakes one bit extra, rounded up to the nearest byte.

中文意思是:

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

照此看来,官方说法是其中一点原因,站在Innodb的行格式上,不见得是省空间的。

作者拙见:

所有使用 NULL 值的情况,都可以通过一个有意义的值的表示,这样有利于代码的可读性和可维护性,并能从约束上增强业务数据的规范性。

NULL 值到非 NULL 的更新无法做到原地更新,更容易发生索引分裂,从而影响性能。

NULL 值在 timestamp 类型下容易出问题,特别是没有启用参数 explicit_defaults_for_timestamp

NOT IN、!= 等负向条件查询在有 NULL 值的情况下返回永远为空结果,查询容易出错,不是自己想要的结果,甚至可能出现重大损失

首发自:https://www.kuya123.com/2021/06/mysql-not-null

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容