说到mysql,首先得先看看mysql支持的存储引擎。mysql支持的引擎很多,以下就常用的几种进行以下介绍。
image.pngInnoDB
https://zhuanlan.zhihu.com/p/103582178
InnoDB是mysql的默认存储引擎,使用InnoDB存储时,会把表的定义存储在.frm文件中,把数据和索引文件存在.idb文件中。5.7以后引入General Tablespace,可以把多个表放到一个文件里
表空间
innodb逻辑存储结构从图上可以看出来,表数据都存储在表空间(Tablespace)中,表空间中又包含段(Segment)、区(Extent)、页(Page)组成。
表空间存在两类
(1)默认情况,数据存储使用公共的表空间ibdate
(2)设置了参数innodb_file_per_table,每个表可以存放在单独的表空间中。当然,也不是所有的数据都支持单独存储,只有数据、索引、插入缓冲Bitmap页可以存放在单据的表空间中,会滚信息,插入缓冲索引页,系统事务信息,二次写缓存还是存储在公共的表空间中
文件管理页
文件管理页结构默认一个extent(1MB)管理64个物理连续的page(16k)。如果page大小小于16k,那么会增加实际的page数量,保持extent大小为1MB;相应的,如果page的大小大于16k,则保持page的数量依旧为64个,extent的大小会大于1MB。
文件管理页的类型是FSP_HDR/XDES(extent descriptor),用于分配、管理extent和page。
FSP_HDR/XDES大小是16k,所以能管理的extent数量是有限的。一般一个FSP_HDR能够管理256个extent(一个extent描述占40字节),表空间文件越大,所需要的的FSP_HDR/XDES页就越多。
FSP_HDR/XDES页内部存储的XDES Entry管理extent的状态,相同状态(一共四种状态)的extent收尾相接,组成了一个双向链表。
extent的状态
- FREE(空)
- FREE_FRAG(至少一个被占用)
- FULL_FRAG(满)
- 归某个segment管理的信息
FSP_HDR和XDES的唯一区别是page 0 的FSP_HDR中包含FSP Header的值,里面存储了四个状态链表(FSP_FREE、FREE_FRAG、FULL_FRAG、FSEG)的头尾数据
INODE页
inode页结构INODE页位于文件的page2上,用于管理segment,每个inode entry负责一个segment。
mysql的数据是按照B+树聚簇索引组织数据的,每个B+数会使用两个segment来管理page,分别是叶子节点segment和非叶子节点segment,这两个segment的inode entry地址记录在B+数的root page中的FSEG_HEADER中,root page又被分配在非叶子segment的第一个碎片页上。
每个segment由32个碎片页(fragment array),FSEG_FREE、FSEG_NOT_FULL、FSEG_FULL组成,这些信息记录在Inode entry里,可以简单理解为Inode就是segment元信息的载体。FREE、NOT_FULL、FULL三个FLST_BASE_NODE对象和FSP_HDR/XDES页里面的FSP_FREE、FREE_FRAG、FULL_FRAG、FSEG概念类似。这些链表被InnoDB使用,用于高效的管理页分配和回收。
碎片页用于优化小表的空间分配。先从全局的碎片空间分配page,当碎片页填满(32)后,每次分配一个完整的extent(1M),如果表大于32M,则一次分配4个extent
INDEX数据索引页
B+树聚簇索引
索引用于快速定位数据。对innodb来说,主键和非主键都是索引,一切数据都存储在INDEX索引页中,索引=数据。
索引可以有多种存储结构,具体如下
- 哈希索引(hash):按key查询性能好,可是需要解决hash碰撞问题,且区间查询不友好
- 有序数组(sorted array):修改不便,只使用与静态存储引擎
- 二叉查找树(binary search tree):更新、查询复杂度都为O(logN)。二叉查找树最大的问题就在于随机IO,所以引入了N叉树
- N叉树:减少了树的高度和随机IO的次数,例如当N=1200,树的高度可以控制在4层,管理1200^3=17亿行。一般根节点在内存,所以最多3次磁盘IO。不仅减少了随机IO次数还保证了查询的稳定性,所以说这种数据结构是一种scales nicely的解决方案。
- 新模型:LSM-tree、跳表skiplist等
聚簇索引和非聚簇索引
一张MySQL表只有一个聚簇索引,聚簇索引可以看做主键,如果建表没有指定主键默认采用第一个NOT NULL UNIQUE INDEX当主键,否则默认6字节的ROW ID做主键。总之InnoDB必须有一个primary key。
使用B+树聚簇索引(B+ tree clustered index)的好处在于:
- 数据和索引顺序一致,充分利用磁盘顺序IO性能普遍高于随机IO的特性。
- 对于局部性查询也会大有裨益。
- 采用B+树,叶子节点(leaf node)存储数据,非叶子节点(non-leaf node)只是索引,这样非叶子节点就会足够的小,因此数据很“热”,便于更好的缓存。
- 对于覆盖索引,可以直接利用叶子节点的主键值。
mysql的二级索引可以看做在非聚簇索引。它的结构也是一颗B+树,叶子节点是指向聚簇索引的主键(可以看成行指针),查询具体数据的时候需要回表
索引页结构
索引页包含主键、二级索引、行和列。B+树的每个节点都是一个INDEX索引页。
聚簇索引:非叶子节点包含主键和child page number,叶子节点包含主键和具体的行
二级索引:非叶子节点包含二级索引和child page numbe,叶子节点包含二级索引和主键值
行由列组成,各种列类型结构encoding编码后才组成了一行
具体模型
image.png微观上把每个页节点内部展开成由infimum和supermum连接起来的有序单链表,结构如下。每层的页通过Fil Header相互连接。
列类型
row format可通过innodb_default_row_format参数指定,也可以在建表的时候指定。
CREATE TABLE tab (
id INT,
str VARCHAR(50)
) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
MyISAM
使用该存储引擎时,数据会在磁盘上存储成三个文件
- frm:存储表的定义
- MDY:存储表的具体数据记录
- MYI :存储索引
frm和MYI允许存放在不同的目录下,MYI文件仅用于索引的存储(仅存储记录所在页的指针,不存储具体的数据),索引的结构为B+树
进行查询操作时,会先根据索引查找到记录页,再把页加载进内存进行具体记录的查找
MEMORY
数据存储在内存中。为了提高数据的访问速度,每个表管理一个磁盘文件(frm)
网友评论