innodb逻辑存储结构
所有数据被逻辑地存放在表空间中,表空间又由段、区、页(有些文档称之为块)、行组成。
段:常见的段有数据段、回滚段、索引段(与约束这种逻辑概念不同,索引是一种数据结构,不止有逻辑上的概念,在数据库中还代表着物理存储的方式。索引段即B+树的非索引节点)等。
innodb由自身完成对段的管理,开发者不能也没必要介入。
区:连续页组成的空间,大小固定1MB。
页:每页至少要存2行数据,行记录太大,就让行溢出。
innodb叶子节点存储的数据,并不是具体某行,而是该行数据所在的页,数据库会把整页数据读入内存,在内存中查找到想要的数据。所以页的大小并非越大越好,太小,管理链表就越长,还有增加IO风险,太大会有占用过多内存风险,默认16KB,可设为4、8KB等。
行:数据最小存储单元。
分区:
分区是将一个表或索引分解为多个更小、更可管理的部分。启用分区后,innodb表由一个ibd文件分为每个分区一个,B+树也是每个分区一个了。
MySQL支持显式的分区选择查询,当你知道增删查改的数据在其中某分区并指出时,mysql会仅查询指定分区。
但是,分区本身大概率会增大一些处理逻辑的复杂度,不仅如此,例如innodb,要处理的业务在多个分区时,你就读了多个B+树,很多时候,mysql的性能瓶颈在磁盘IO过多,此时只分区不分表无太大帮助,反而有增大IO风险。
mysql支持水平分区,不支持垂直分区(官方8.0文档中说,目前并没有支持垂直分区的计划)。同一分区表的不同分区需要用同一引擎,在MySQL 8.0中,支持分区的存储引擎是InnoDB和 NDB,仅InnoDB 存储引擎提供了本机分区处理程序。
表中存在唯一或主键索引时,分区列必须是每个唯一索引的一个组成部分。部分MySQL函数在分区后不被支持。
分区类型:
range(范围):给定连续区间来区分
list(列表):给定离散值区分
hash(哈希):根据用户自定义表达式的返回值区分
key(密钥):根据mysql的hash函数区分
columes(组合列):(range columes/list columes):基于多个列值来定义分区,这些列值可以非整型。
range columes与range区别:
range columes 不接受表达式,仅接受列名,接受一个或多个列的列表,RANGE COLUMNS分区列不限于整数列;字符串, DATE、 DATETIME列也可以用作分区列。
list columes与list区别:
允许将多个列用作分区键,并且可以将整数类型以外的数据类型的列用作分区列;您可以使用字符串类型 DATE,和 DATETIME列。
Sub(子分区/复合分区):分区表中每个分区的进一步划分
行格式:
InnoDB存储引擎支持四种行格式:redundant(冗余), compact(紧凑), dynamic(动态),compressed(压缩),mysql5.7和mysql8默认dynamic(可由innodb_default_row_format设置;show table status like '表名'查看;SET GLOBAL innodb_default_row_format=dynamic 设置)。
dynamic、compressed为新的页格式,对于存放在BLOB中的数据采用了完全行溢出方式,在数据页中只存放指针,实际数据都在溢出页中,避免了用大量长列数据字节填充B树节点的问题,而之前的compact、redundant会存放部分前缀字节在数据页。
(另:前缀索引只能适用于普通索引中,不能使用在unique中,前缀索引只支持英文和数字)
除了compressed(压缩),其他都可设为默认值,系统表空间不支持 compressed行格式。(但可以手动把需要的库表设为compressed)
![在这里插入图片描述]()
第三列标题:增强的可变长度列存储
大字段带来的行溢出会增加一次寻址,它作为where条件时不能使用索引,所以在一般开发中可以纵向分表,把大字段单独存放。
(第三列:增强的可变长度列存储)
https://dev.mysql.com/doc/refman/8.0/en/innodb-row-format.html