了解数据存储空间占用,可以更方便我们再企业中对于数据库相关优化做评估。
首先这里准备一张数据库表约2.3w数据量:
CREATE TABLE `project` (
`tenantsid` bigint(20) NOT NULL DEFAULT '0' COMMENT '租户ID',
`project_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`code` bigint(20) NOT NULL DEFAULT '0' COMMENT '项目编号',
`name` varchar(72) COLLATE utf8_bin DEFAULT '' COMMENT '项目名称',
PRIMARY KEY (`project_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=59840 DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='项目档'
查看表存储空间大小方式有很多
1、通过iinformation_schema.tables查看数据空间占用信息
select table_name,data_length,index_length from information_schema.tables where table_name = 'project';
按照官网介绍:
DATA_LENGTH
对于MyISAM
,DATA_LENGTH
是数据文件的长度,以字节为单位。
对于InnoDB
,DATA_LENGTH
是为聚集索引分配的大约空间量(以字节为单位)。具体来说,它是聚集索引大小(以页为单位)乘以InnoDB
页大小。
INDEX_LENGTH
对于MyISAM
,INDEX_LENGTH
是索引文件的长度,以字节为单位。
对于InnoDB
,INDEX_LENGTH
是为非聚集索引分配的大约空间量(以字节为单位)。具体来说,它是非聚集索引大小的总和(以页为单位)乘以 InnoDB
页大小。
DATA_LENGTH = 聚集索引大小(以页为单位)乘以InnoDB
页大小
INDEX_LENGTH = 非聚集索引大小(以页为单位)乘以InnoDB
页大小
2、查看page页大小配置
show status like '%page_size%';
可以看到默认的页大小为16kb
3、查看当前project表聚簇索引使用了多少page
innodb_space -s ibdata1 -T firestation/project space-indexes
可以看到这里面PRIMARY一共分配了97个page页占用空间 = 97*16*1024 = 1,589,248可以看到正好是DATA_LENGTH大小
前面也说到了当97个表只是当前project真实数据占用的空间大小,对于表来说,还存在其他的的空间占用,比如缓存、元数据等等,所以DATA_LENTGTH表示的只是真实数据的大小。当然对于日常的空间占用评估是足够了。
那我们深入探索下,project真实存储空间占用情况。
4、查看project表使用总page数
innodb_space -s ibdata1 -T firestation/project space-page-type-summary
可以看到project实际存储时使用到了704个page页,所以理论上应该占用空间704*16*1024=11,534,336
其实mysql在information_schema中提供了innodb系列的元数据表,它记录了innodb底层存储时真实的元数据信息,例如information_schema.innnodb_sys_tablespace(我这里是mysql5.7不同版本的名称不同,看官网说明)中就可以查看表真实存储空间大小。
5、查看project真实占用空间大小
select * from information_schema.innodb_sys_tablespaces where name = 'firestation/project';
FILE_SIZE
文件的表观大小,表示未压缩的文件的最大大小。
ALLOCATED_SIZE
文件的实际大小,即磁盘上分配的空间量。
可以看到这里的File_size就是上面通过真实数据page数计算出来的结果。
所以结论:
1、可以通过information_schema.table查看DATA_LENGTH,这个为当前主键索引也就是真实数据的空间占用大小。
2、可以通过information_schema.innodb_sys_tablespace 查看File_size,这个为当前project总占用空间大小
其实通过上述的结论,就可以大致的评估出每行数据空间占用大小,总大小/行数,这里我们更深入了解下一行数据怎么计算的空间占用大小。
1、查看每一行数据占用空间大小
(1)首先先确定project存储tree一共为几层 , 这里先介绍一种查看到方式,后续在介绍另一种。
通过innodb_space工具查看:
这里可以看到PRIMARY索引一共分2层,第1层非叶子节点只有一个page,第2层叶子节点共95个page页,需要注意的是这里叶子节点为0层,依次往上推。
(2)查看每一层tree空间占用
1层,非叶子节点(此处为root节点):
innodb_space -s ibdata1 -T firestation/project -I PRIMARY -l 1 index-level-summary
page: page页编号,这里为3,也就是上面看到的root节点page编号
index:索引编号
level:当前page所处的层级
data:当前page占用空间大小
free:当前page空闲空间大小,因为page大小固定16kg,所以就会存在页用不满的现象
recoreds:当前page存储的数据行数,这里因为是非叶子节点,所以指的是主键行数。
min_key:当前页中最小的索引列,这里是主键。
0层,非叶子节点(此处为root节点):
从这里就可以看出来,大约每行数据占用15000/250 = 60字节空间
行空间占用和字段数据有密切的关系,如果字段占用空间小(比如字段栏位少,无长文本字段等)那page可以存储更多的行数,整体的占用空间小,B+树层级少,查询速度快。
这里以page#5为例,看下当前page页空间分布说明:
innodb_space -s ibdata1 -T firestation/project -p 5 page-illustrate
这张图就是展示了PAGE一个详细的空间结构,前面文章也介绍过,这里不再赘述。
可以看到Record Header + Record Data 是真实数据产生的空间占用 = 1631+13471 =15102也是验证了上面看到的page空间占用。
三、每行数据空间评估
根据上面的数据结果,选择一个project_id = 33819的一行数据,从空间上来看为15102字节/233 =64字节
当前行数据:
我们知道bigint占用8字节,varchar是不定长,一个汉字3字节。按照这样的算法
空间:8+8+8+12 = 36字节,远小于60字节,这是为什么呢?
这个就是需要了解行格式知识相关了:【Mysql】 InnoDB引擎深入- 行格式_mysql 5.6 innodb引擎 不支持行格式为:dynamic_Survivor001的博客-CSDN博客
首先确定我们目前的行格式是什么,这个很好确定:
根据行格式的知识,我们知道一行数据除了真实的数据之外还会记录一些额外的信息。