MySQL 四.数据库表存储结构&表空间

1.索引组织表

数据的存储是按照主键顺序来的;在InnoDB,每个表都有主键 Primary Key;若没有显示设置,会默认设置主键

  • 唯一索引为主键
  • 上述不满足 创建一个6byte 的指针

2.InnoDB逻辑存储

在这里插入图片描述

2.1 表空间

tablespace 前面说过了如果配置了innodb_file_per_table=ON 就是一张表一个表空间

但是呢 这样每张表的表空间存储的数据有:表数据,索引,insert buffer bitmap

但是,张表的其他的信息,比如回滚信息,插入缓存索引页,二次写缓存还是会存在共享表空间ibdata1;

ibdata1初始大小是58M;后续不够会变大,但是后续不需要这么大的时候不会变小;

2.2 段

数据段 Leaf node segment

索引段 Non-Leaf node segment

回滚段

段是由存储引擎管理

2.3 区

Extent 每次申请磁盘会申请4-5个区 ;一个区1MB对应64个page (16K) ;可以配置page 的大小 ,但是区始终是1MB;

创建表后 表空间为96K?

三个段 一个段 32kB 当32KB 使用完成后才回去申请连续的64个页;节约磁盘开销;

2.4 页

Page 也叫块 block默认是16KB 大小

2.5 行

InnoDB是基于行数据存储的 row-oriented ;存放16Kb/2 - 200 = 7992行数据

3.InnoDB行记录格式

InnoDB存储引擎提供 Compact 和Redundant 两种格式来记录数据;

3.1 Compact

数据存储的格式为
在这里插入图片描述

变长字段长度列表:就是一行数据从后面数第一个列是变长的,比如是varchar(50) 类型,然后数据存的是‘aaa’ 就对应00000011

然后倒数第二个 变长的如果是‘eeeee’ 对应 00000101; 以此类推 有几个变长字段,变长字段长度列表就在后面加几个;

null 标志位 一个字节 1 表示行数据内有null;也就是说我的表的数据列设置了可以空的超过8时 ;会多出一个字节来表示null 标志位;

如下表;null 的标志位为 0x035A ==> 0000 0011 0101 1010 ===>反过来就是 下面第三行数据

t1t2t3t4t5t6t7t8t9t10
aNULLbNULLNULLcNULLdNULLNULL
0101101011

在这里插入图片描述

记录头信息 5byte

在这里插入图片描述

还有事务id 列 6byte

回滚指针列 7byte

如果没有定义主键 还有rowid 列:6byte

测试:

create table test
(
    t1 varchar(10),
    t2 varchar(10),
    t3 varchar(10),
    t4 char(10)
) engine = innodb
  row_format = compact;

数据

t1t2t3t4变长标志位null标志位
abbcccNULL03,02,0100001000:08
aNULLbbNULL02,0100001010:0A
NULLcccdddNULL03,0300001001:09

对应字节文件

在这里插入图片描述

解读:

第一行数据对应

03 02 01 :变长字段长度列表

08 :null 标志位

00 00 10 00 21 :Header

00 00 00 00 02 09 :rowID 没有指定主键的roeid

00 00 00 34 db cd : transcationID 事务id

be 00 00 01 40 01 10 : roll pointer 回滚指针

61 :a

62 62 :bb

63 63 63 :ccc

null 不占用存储部分字节 本行解析结束 其他两行差不多;

3.2 Redundant

兼容MySQL5.0之前的版本;

在这里插入图片描述

不同点:变长的使用了偏移量

在这里插入图片描述

CHAR 占用固定长度字符;

varchar 不占用

3.3 行溢出数据

MySQL数据库说可以存放 65535 字节,测试下来65535 不行,实际值要偏小一点为65532

###失败
easytaxi> create table charTest
          (
              t1 varchar(65535))
[2021-09-30 10:45:58] [42000][1118] Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs

###成功
easytaxi> create table charTest
          (
              t1 varchar(65532))
[2021-09-30 10:46:21] completed in 221 ms

修改编码

easytaxi> create table charTest1
          (
              t1 varchar(65532)
          ) charset =GBK engine=innodb
[2021-09-30 10:51:07] [42000][1074] Column length too big for column 't1' (max = 32767); use BLOB or TEXT instead
[2021-09-30 10:51:07] [42000][1074] Column length too big for column 't1' (max = 32767); use BLOB or TEXT instead
easytaxi> create table charTest1
          (
              t1 varchar(65532)
          ) charset =utf8 engine=innodb
[2021-09-30 10:51:34] [42000][1074] Column length too big for column 't1' (max = 21845); use BLOB or TEXT instead
[2021-09-30 10:51:34] [42000][1074] Column length too big for column 't1' (max = 21845); use BLOB or TEXT instead

可以看出varchar(N) N 指的是字符 不是字节;

easytaxi> create table charTest2
          (
              t1 varchar(65500),
                  t2 varchar(65500)
          ) engine=innodb
[2021-09-30 10:58:17] [42000][1118] Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs
[2021-09-30 10:58:17] [42000][1118] Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs
easytaxi> create table charTest2
          (
              t1 varchar(65500),
                  t2 varchar(2)
          ) engine=innodb
[2021-09-30 10:58:24] completed in 201 ms

而且65535 长度是所有varchar列加起来不能成超过;

思考 一个页数据最大就16384字节 怎么可以存放65532字节呢?

一般情况下 ,数据页都是在b_tree 的叶子节点上面,但是呢如果有行数据溢出超过了页的大小,那么溢出数据就会存放在表空间的Uncompress BOLB 页里面

又引入问题:溢出数据量如何控制;varchar 大小有个最大值 8089 ;小于这个都是存放在数据页中;

如果存放的数据导致行溢出,数据也最多只会存放768byte

3.4 Compressed 和Dynamic 行记录格式

Antelope :Compact 和Redundent

Barracuda: Compressed 和Dynamic :BLOB 数据类型相比较就是完全溢出的方案 原本列报错的数据为20z字节的指针 实际的数据存储与OFF page 里面;Compressed 的类一个功能就是数据会zlib压缩

3.5 CHAR 存储结构

编码字符字节
latin111
GBK12
UTF-813

对于多字节的字符编码 UTF-8 GBK; char存储就是动态的字节大小了;比如utf-8 如果存字母 10字节 汉字的话就是30个字节了,char这个时候就算是变长字符串了;

实例char(5) gbk 20 是补得空格

编码字节
aaaaa61 61 61 61 61
我们我们我c3 d2 c3 c7 c3 d2 c3 c7 c3 d2
aa61 61 20 20 20
我们c3 d2 c3 c7 20 20 20 20 20 20

char对满足长度的会补0x20 其他的 对于多字符编码的存储 char 和varchar 没什么区别了,char 也会被认为是变长的;

4.InnoDB数据页格式

  • File Header :38byte

  • Page Header:56byte

  • infimun supremun Records

  • User Records

  • Free Space

  • Page Directory

  • File Trailer: 8byte

在这里插入图片描述

4.1 File Header

在这里插入图片描述

在这里插入图片描述

4.2 Page Header

在这里插入图片描述

4.3 infimun supremun Records

infimun Records 和supremun Records 是两个虚拟的行记录

在这里插入图片描述

4.4 User Records Free Space

User Records 实际行存储的内容

Free Space 空闲空间

4.5 Page Directory

4.3 可以看到一个页里面的数据为

infimun 记录1 记录 2 … 记录n supremum

Page Directory 就是相当于存放了这些记录的相对位置 一个个的slot;n_owned 中的n是slot 的槽位内部存储记录的个数 ;会随着数据插入solt 会进行分裂

开头的slot 存储infimun n=1

中间 的 n = [4,8]

最后supremum n = [1,8]

B+ tree 索引本省并不能找到具体的一条记录,只是能找到记录对应的数据页;找到页后加载到内存,然后再通过Page Directory 二分查找,内存中运行很快,故时间很少;

4.6 File Trailer

主要是检测数据页完整性 这里面的字段fil_page_end_lsn ;前面4byte=checksum 后4byte 和header 的fil_page_lsn 和header里面的file_page_apace_or_checksum 和 fil_page_lsn 比较;默认配置每次读取页的时候都需要对比;

4.7 示例分析

create table t(
    a int unsigned not null primary key  auto_increment,
    b char(10)
)engine =innodb charset =UTF8;
ab
1aaaaaaaaaa
2bbbbbbbbbb
3cccccccccc
4dddddddddd
5eeeeeeeeee
6ffffffffff
7gggggggggg
8hhhhhhhhhh
9iiiiiiiiii
10jjjjjjjjjj

在这里插入图片描述

初始文件大小t.idb 为96K ;InnoDB最小管理单元是16K ,可以得到6个页;开始位置分别是 地址 00000000;00004000;00008000;0000c000;

00010000,00014000;根据头部偏移量24 字节后 为0x45bf 为数据页定位到数据页开始为0000c000;

数字含义
41 71 8b 28FIL_PAGE_SPACE_CHECKSUM4:数据页checksumfile header
00 00 00 03FIL_PAGE_OFFSET4:页的偏移量f
ff ff ff ffFIL_PAGE_PREV4:没有上一页f
ff ff ff ffFIL_PAGE_NEXT4:没有下一页f
00 00 00 09 68 8d ce 18FIL_PAGE_LSN8:LSN 日志序列f
45 bfFIL_PAGE_TYPE2:代表是数据页f
00 00 00 00 00 00 00 008:无效f
00 00 00 57SPACE4:space idf
41 71 8b 28file trailer前四个字节
checksum函数比较
4:File Trailer
68 8d ce 18file trailer后四个字节
Lsn 相等
4:File Trailer
00 03slot 数量2:Page header
70 00 e5 00 63 413个槽 一个2字节2*3:p
01 cc空闲开始偏移量
0x0000c000+0x01cc
0x0000c1cc 之后都是空闲
2:确实是p
80 0cpage_n_heap2:c:12 条
减去infimun和supremun为10条
p
00 00page_free2:没有删除 0p
00 00page_garbage:2:没有删除 0p
01 b1page_last_insert没有删除 0p
00 02page_driection2:连续插入 右 02p
00 09page_n_driection2:连续插入条目p
00 0apage_n_recs2:页中记录
00 00 00 00
00 00 00 00
page_max_trx_id8:事务id
00 00page_level2:叶子节点0
00 00 00 00
00 00 00 fd
page_index_id8:索引id
00 00 00 57 00 00 00 02 00 f2 00page_btr_sge_leaf:10:非页节点segment header
00 02 00 1c 69 6e 66 69 6d 75page_btr_sge_top10:段segment header

在这里插入图片描述

5.Named File Formats 机制

略略略。。。。。

6.约束

6.1 完整性约束

  1. 实体完整性: 主键或者是唯一约束

  2. 域完整性 : 字段的约束 合适的类型,外键,触发器,default

6.2 约束的创建和查找

在创建表的时候创建 alter table 创建

6.3 约束和索引的区别

约束是一个逻辑概念,索引是数据结构,存储在物理磁盘

6.4 对错误数据的约束

数据库允许非法的或者不准确的数据插入或者更新;

6.5 Enum 和set 的约束

create table a(
   id int  primary key auto_increment,
   sex ENUM('nan','nv')
)

6.6 触发器和约束

用触发器实现约束不建议;

6.7 外键约束

也不建议;数据库更新风暴

7.视图

可以看做是一个虚表 由一个查询SQL 定义

7.1 视图的作用

虚拟表 查询方便 ;不需要关系原来的表的定义和结构

7.2 物化视图

MySQL本身不支持 触发器自己去实现也不建议

8.分区表

8.1 分区概念

功能不是在存储引擎层面完成的:一个表或者索引分为几个更小的部分;逻辑上看还是一张表,或者一个索引,但是在物理存储的层面可能是分成了很多的物理单元,也叫物理分区,一个分区页可以作为独立的对象处理;

只支持水平分区:不同行的记录分到多个物理文件中;不支持垂直分区;

支持局部分区索引:一个分区中数据和索引在一起; 不支持全局分区

8.2 分区类型

1. RANGE 分区

没有命中分区会报错

测试 1 :根据id 大小分区

create table b(
    id int  primary key auto_increment,
    sex ENUM('nan','nv')
)engine =innodb charset =UTF8
    partition by range(id)(
        partition po values less than(10),
            partition p1 values less than(20)
        )
        
-- b#p#p1.ibd
-- b#p#p0.ibd

每个分区都有对应的ibd 文件;

测试2 按照时间分区

删除数据可以转换为直接删除时间对应的分区

注意:1. 要根据分区特性来编写最优的SQL 语句;

​ 2.优化器对应部分函数有优化选择 分区函数优先使用优化过的函数分区 比如 to_days(),year() 等;

2.List 分区

没有命中分区会报错; 分区值是离散的 不想是renge 一样是会有连续的

create table  c(
    id int  primary key auto_increment,
    sex ENUM('nan','nv')
)engine =innodb charset =UTF8
    partition by List(id)(
        partition po values  in (1,3,4,6),
            partition p1 values in (5,2,7)
        )

3.Hash 分区

数据均匀分布到预先定义的分区中,保证数据量大体一致;by hash ( expr) expr为一个整数列或者运算后的为整数的表达式 partitions 4; mysql 会自动的把数据发到4个分区

create table d
(
    id  int primary key auto_increment,
    sex ENUM ('nan','nv')
) engine = innodb
  charset = UTF8
    partition by hash ( id )
partitions 4;

4.key 分区

和hash 差不多 只是 key 的里面不能时函数了 只能是列了 ,mysql对应有响应的算法自己来计算;

create table d
(
    id  int primary key auto_increment,
    sex ENUM ('nan','nv')
) engine = innodb
  charset = UTF8
    partition by key ( id )
partitions 4;

5.colnum分区

支持所有整型

日期类型

字符串类型

指定多个列分区

8.3 子分区

分区上面在分区 也叫复合服务(在range 和list 上面进行 hash 或key)

8.4 分区处理NULL

插入null 分区函数无法判断

RANGE 分区插入null 放入左边分区

List 分区null 需要指定分区插入

Hash key分区函数会放回0

8.5分区性能

考虑B+tree 的层级的影响在分区 一般千万级别的数和几十万数据 树的层级都是三层,分区并不能带来很好的查询速度提升;

8.6 表和分区交换数据

分区或者子分区的数据和另一个非分区表中的数据进行交换;

alter table …exchange partition

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值