前言
通过阅读本文你可以了解下面几个问题:
- 对于null值在mysql中具体是怎么存储的
- null可以使用到索引吗
NULL的存储
准确的来说mysql的数据存储都是底层存储引擎的工作,所以这个问题取决于你使用的存储引擎,这里参考Stack Overflow上面的一篇解答。
MyISAM存储引擎
Myisam的每一条记录都会有一个记录头(record header),其中若干个比特位来标识字段是否为null。
具体内容如下:
- "X bit" = 0 if row is deleted, = 1 if row is not deleted
- "Null Bits" = 1 if row contains any null fields, or = 0 otherwise.
- "Filler Bits" = 1
记录头的总长度为:(1 + number of NULL columns + 7) / 8 bytes
对于myisam即使字段为null,也会占据存储空间。
由于现在广泛使用的都是InnoDB存储引擎,所以这里不过多展开。原文请参考官方文档:dev.mysql.com/doc/interna…
InnoDB存储引擎
首先我们要知道InnoDB里面的数据存储分为聚簇索引(主键索引)树与非聚簇索引(二级索引),同时InnoDB都是以页为单位进行读写的,下面对于聚簇索引的页子结点我们称之为数据页,里面存储的是一行行数据,对于二级索引的叶子节点我们称之为索引页,里面存储的是一行行索引记录(索引值+主键值)。
对于InnoDB的null如何存储取决于InnoDB 表的Row Formats配置,对于MySQL 5.0.3 到 MySQL 5.7.8默认的row format都是COMPACT,
use information_schema; -- 切换到mysql内置的元数据管理数据库
SELECT * FROM TABLES WHERE TABLE_SCHEMA = 'databaseName' and TABLE_NAME = 'tableName'\G; -- 查看表的row format配置
复制代码
DYNAMIC与COMPACT类似,只是提供了一些增强,参考至官方文档:
The DYNAMIC
row format offers the same storage characteristics as the COMPACT
row format but adds enhanced storage capabilities for long variable-length columns and supports large index key prefixes.
对于COMPACT row format来说,其会在每一行记录前专门有若干个比特位来标识字段是否为空。这些比特位占据 CEILING(N / 8)
个字节,其中N为nullable列的个数。对于非空列当然则不需要比特位来标识null与否。
更加详细的关于COMPACT的存储结构的介绍,可以参考这篇博客:blog.jcole.us/2013/01/10/… format。
Null是否可以使用到索引
在MySQL官方文档(5.7版本与8.0版本)中明确说明is null可以进行与等值查询一样的优化。
参考文档
-
stackoverflow 关于null的存储问题,stackoverflow.com/questions/2…
-
MySQL COMPACT row format物理存储结构,blog.jcole.us/2013/01/10/…