200_mysql_innodb_1_ Row_Format _page_聚簇_二级索引
前言;
1 Innodb 核心特性
MVCC : 多版本并发控制
聚簇索引 : 用来组织存储数据和优化查询
支持事务 : 数据最终一致提供保证
支持行级锁 : 并发控制, 保障 写 – 写之间的控制,保障一致性
外键 : 多表之间的数据一致一致性 多缓冲区支持
自适应Hash索引: AHI 复制中支持高级特性。
备份恢复: 支持热备。
自动故障恢复:CR Crash Recovery
双写机制 : DWB Double Write Buffer
2 查询版本
#客户端版本
mysql -V
#server 版本
select @@version; engine 版本:
SELECT * FROM information_schema.plugins;
SELECT @@innodb_version;
一 宏观结构
8.0 以前 InnoDB表: ibd数据和索引; frm :存私有的数据字典信息; ibdataN:系统的数据字典信息
8.0 之后只有ibd数据和索引+ 冗余的SDI私有数据字典信息 (对DDL有好处) SDI(每个表的表空间自行管理json格式的私有数据字 典信息,用来替换frm的。)
mysql.ibd ---> 整个系统的数据字典,不再放在ibdata1
二 微观物理结构
2.1 innodb记录存储结构
Innodb数据页16KB (show variables like "innodb_page_size"; #16384 16KB) 一次至少从磁盘读取16KB到内存,一次最少刷新16KB内容到磁盘
2.2 Innodb 行格式 Row_Format (Redundant Compact Dynamic Compressed)
show variables like "%Row_Format%" # innodb_default_row_format dynamic
create table xxx() ROW_FORMAT=DYNAMIC
2.3 行格式的机构
1 记录额外的信息 (132字节)
- 变长字段长度信息: 列表形式 存储所有可变长度字段(varchar TEXT)的真实数据(非NULL)占用的字节数 (逆序存放)
- NULL值列表: 二进制表示 1为null,0位非null (先判断表约束,然后根据实际情况 逆序存放 最终转成16进制)
- 记录头信息:5个字节(40个二进制位)组成 描述该记录的属性
名称 |
大小(bit) |
描述 |
预留位1 | 1 | 没有使用 |
预留位2 | 1 | 没有使用 |
delete_mask | 1 | 标记该记录是否被删除,0 表示未删除,1表示删除, |
min_rec_mask | 1 | B+树的每层非叶子节点中的最小记录都会添加该标记 (只有目录项_非叶子节点存储此信息 1 表示,其它是0) |
n_owned | 4 | 表示当前记录拥有的记录组数 带头大哥的组数为实际组数,小弟为0 |
heap_no | 13 | 表示当前记录在记录堆的位置信息 (user records中heap一条条亲密无间排列的结构,每条记录在heap中的位置heap_no) |
record_type | 3 | 表示当前记录的类型,0表示普通记录,1表示B+树非叶子节点(目录项)记录,2表示Infimum最小记录,3表示Supermum最大记录 |
next_record | 16 | 表示下一条记录的相对位置 |
备注:
- 记录可以比大小,比的是主键
- 无论插入多少条记录,最小是Infimum (5字节记录头+8字节固定单词), 最大是Supremum
- Next record 当前记录到下一条记录的真实距离(理解为偏移量/指针 正数代表在下一条记录后面,负数代表前面, -111代表向前找111个字节)
- 无论对数据的增删改,innodb始终维护一个单项链表(链表各个节点由主键从小到大顺序链接)
- 页面前面的记录heap_no小,后面大,从2开始, 0-Infimum;1-Supremum最靠前
2 真实记录数据
- Row_id 6字节 ,行ID 唯一表示一条记录 非刚需,无主键情况下生成(无显示定义,可以选not null & UNIQUE的键)
- Trx_id 6 字节 事物ID 刚需
- Roll_pointer 7字节 回滚指针
溢出列
某列超出数据页范围 需在其他页面存储,其它页面即为溢出列(COMPACT&REDUNDANT格式 会存储真实记录的 768字节,再拿20字节存储其它位置的指针等信息)
溢出页临界点(MySQL中规定,一个也至少存两行记录 每行记录真实数据的属性信息27字节) 132+2(27+n)< 16384 , n <8099 情况下不会有溢出列
DYNAMIC格式不会单独记录真实数据的前768个字节,仅拿20字节存储溢出页/列的位置
三 Innodb数据页结构
InnoDB存放不同数据页设计不同类型的页, 例如 index 页 Change buffer页,Inode页,undo页, 通用结构如下
3.1 Page Directory
Select * from xxx where id = xxx不会从infimum开始遍历,innodb会设计一种 类似书的目录结构,
- 将正常记录分成几组(包括infimum & supremum)
- 每组最后一条也是最大记录是带头大哥,其余数据属于这位大哥(n_owned=0)
- 带头大哥在页面中的偏移量(实际位置到第0个字节距离)取出,放在整改页的尾部(page directory) 这些偏移量成为槽 slot(每个slot2字节,相邻分布,越小越接近File Trailer)
- Infimum所在组只能有1条记录,supremum所在组 1-8条, 剩下正常组 4-8条
3.2 PageHeader 记录数据页中的状态信息 例如 Free space 偏移量,slot个数等
状态名称 | 占表空间 | 描述 |
PAGE_N_DIR_SLOTS | 2字节 | 在Page Directory(页目录)中的Slot(槽)数 |
PAGE_HEAP_TOP | 2字节 | 还未使用最小空间,在这之后就是Freespace |
PAGE_N_HEAP | 2字节 | 第一位标记是否为紧凑型记录, 其余15位表示堆中的记录数 (包括infumum supremum 以及已删除记录) |
PAGE_FREE | 2字节 | 已经删除的记录通过next_record组成一个单向链表, 其中所占用存储空间可以重用, page_free表示该链表头结点在页面中偏移量 |
PAGE_GARBAGE | 2字节 | 已删除记录的字节数,即行记录结构中,delete flag为1的记录大小的总数。 |
PAGE_LAST_INSERT | 2字节 | 最后插入记录的位置 |
PAGE_DIRECTION | 2字节 | 最后插入的方向。可能的取值为PAGE_LEFT(0x01),PAGE_RIGHT(0x02),PAGE_SAME_REC(0x03),PAGE_SAME_PAGE(0x04),PAGE_NO_DIRECTION(0x05)。 |
PAGE_N_DIRECTION | 2字节 | 一个方向连续插入记录的数量。 |
PAGE_N_RECS | 2字节 | 该页中记录的数量(不包括已经删除记录和 infumum & supremum) |
PAGE_MAX_TRX_ID | 8字节 | 修改当前页的最大事务ID,注意该值仅在Secondary Index定义 |
PAGE_LEVEL | 2字节 | 当前页在B+树种所处的层级 |
PAGE_INDEX_ID | 2字节 | 当前页属于哪个索引ID。 |
PAGE_BTR_SEG_LEAF | 10字节 | B+树的叶节点中,文件段的首指针位置。注意该值仅在B+树的Root页中定义。 |
PAGE_BTR_SEG_TOP | 10字节 | B+树的非叶节点中,文件段的首指针位置。注意该值仅在B+树的Root页中定义。 |
3.3 File header (文件头部信息 记录数据页记录的各种状态)
状态名称 | 占表空间 | 描述 |
FIL_PAGE_SPACE_OR_CHKSUM | 4字节 | 当MySQL版本小于MySQL-4.0.14,该值代表该页所在表空间ID ,之后该值代表页的checksum值(一种新的checksum值)。 |
FIL_PAGE_OFFSET | 4字节 | 页号 (单独页号类似身份证) |
FIL_PAGE_PREV | 4字节 | 上一个页号 双向链表 |
FIL_PAGE_NEXT | 4字节 | 下一个页号 B+Tree特性决定了叶子节点必须是双向列表 |
FIL_PAGE_LSN | 8字节 | 页面最后被修改后修改时候的LSN(Log Sequence Number) |
FIL_PAGE_TYPE | 2字节 | 页的类型 请记住0x45BF,该值代表了存放的数据页 |
FIL_PAGE_FILE_FLUSH_LSN | 8字节 | 该值仅在系统表空间的第一页中定义,代表文件至少被更新到了该LSN值 |
FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID | 4字节 | 该值代表页属于哪个表空间 |
数据页类型
类型名称 |
十六进制 |
描述 |
FIL_PAGE_TYPE_ALLOCATED |
0x0000 |
最新分配,还没使用 |
FIL_PAGE_UNDO_LOG |
0x0002 |
Undo 日志页 |
FIL_PAGE_INODE |
0x0003 |
存储断的信息 |
FIL_PAGE_IBUF_FREE_LIST |
0x0004 |
Change Buffer空闲列表 |
FIL_PAGE_IBUF_BITMAP |
0x0005 |
Change Buffer 的一些属性 |
FIL_PAGE_TYPE_SYS |
0x0006 |
存储一些系统数据 |
FIL_PAGE_TYPE_TRX_SYS |
0x0007 |
事务系统数据 |
FIL_PAGE_TYPE_FSP_HDR |
0x0008 |
表空间头部信息 |
FIL_PAGE_TYPE_XDES |
0x0009 |
扩存储区的一些属性 |
FIL_PAGE_TYPE_BLOB |
0x000A |
溢出页 |
FIL_PAGE_INDEX |
0x45BF |
索引页,也就是数据页 |
3.4 File Trailer (文件尾部) 为了检测页是否已经完整地写入磁盘(如可能发生的写入过程中磁盘损坏、机器关机等)
8个字节组成 分成2部分
前四个字节 代表也的校验和 通File Header中的校验和对应
后四个字节 代表页面被最后修改时 对应的LSN的后四个字节 同FILE_PAGE_LSN后四个字节相同
四 Innodb存储引擎索引_B+树索引
表在插入过程中,分配的数据页不一定是连续的,由于主键索引从小到大排序,所以会有页的分裂产生,为了快速查找,制作目录(非叶子节点)
- 页的用户记录中最小的主键值 作为key
- 页号 用page_no 表示
B+ 树的根节点自创建日后不再移动
聚簇索引 主键的大小作为页和记录的排序规则, 叶子节点记录包含表中所有列
二级索引(辅助索引) 索引列(字段)的大小作为页和记录排序规则, 叶子节点存储的是索引列和主键
MyISAM 存储引擎的数据和索引分开存储, 索引均为二级索引,叶子节点存储的是列+行号
4.1 聚簇索引 使用主键的大小作为页和记录的排序规则
- 页(包括叶子节点和内节点) 内的记录安装主键大小排序 –> 单向链表
- 各存放用户记录的页节点也根据用户记录的主键大小排序 –> 双向链表
- 存放目录项的页 层级不同,同层级中页也是根据目录项的主键大小排序 –>双向链表
- B+树的叶子节点存储完整用户记录包括隐藏列
4.2 二级索引 单独一颗B+数 叶子节点存储列和主键ID以及页号
如果联合索引a1 a2 a3 会先按a1排序,a1相同a2排序,a2相同a3排序, 再对应主键(顺序打乱,随机IO)
创建索引
alter table t1 add index idx_k2(k2);
alter table t1 add index idx_k1_2(k1,k2);
alter table city add index idx_n(name(5)); # 前置索引
alter table city drop index idx_n
- 点赞
- 收藏
- 关注作者
评论(0)