MySql
1.存储引擎
1.1 mysql 存储引擎的选择
存储引擎 | 描述 |
---|---|
ARCHIVE | 用于数据存档(数据插入后不可修改) |
BLACKHOLE | 丢弃写操作,读操作会返回空数据 |
CSV | 在存储数据时,以逗号分隔个个数据项 |
FEDERATED | 用来访问远程表 |
InnoDB | 支持事务、行级锁、外键 |
MEMORY | 数据只存储在内存,不存储在磁盘:多用于临时表 |
MERGE | 用来管理多个 Myl SAM 表构成的表集合 |
MylSAM | 主要的非事务处理存储引擎 |
NDB | MySQL 集群专用存储引擎 |
1.2 存储引擎对部分功能的支持情况
功能 | MylSAM | MEMORY | InnoDB | ARCHIVE | NDB |
---|---|---|---|---|---|
B-tree indexes | 是 | 是 | 是 | 否 | 否 |
Baclcup/point-in-time reCQve | 是 | 是 | 是 | 是 | 是 |
Cluster database support | 否 | 否 | 否 | 否 | 是 |
Clustered indexes | 否 | 否 | 是 | 否 | 否 |
Compressed data | 是 | 否 | 是 | 是 | 否 |
Data cacbes | 否 | N/A | 是 | 否 | 是 |
Encrypted data | 是 | 是 | 是 | 是 | 是 |
Foreign key support | 否 | 否 | 是 | 否 | 是 |
Full-text searcb indexes | 是 | 否 | 是 | 否 | 否 |
Geospatial data type support | 是 | 否 | 是 | 是 | 是 |
Geospatial indexing support | 是 | 否 | 是 | 否 | 否 |
Hasb indexes | 否 | 是 | 否 | 否 | 是 |
lndex caches | 是 | N/A | 是 | 否 | 是 |
Locking granularity | 是 | 是 | 是 | 是 | 是 |
MVCC | 否 | 否 | 是 | 否 | 否 |
Query cacbe support | 是 | 是 | 是 | 是 | 是 |
Replication support | 是 | 有限支持 | 是 | 是 | 是 |
Storage limits | 2S6TB | RAM | 64TB | 无存储限制 | 384EB |
T-tree indexes | 否 | 否 | 否 | 否 | 是 |
Transactions | 否 | 否 | 是 | 否 | 是 |
Update statistics for data dictionary | 是 | 是 | 是 | 是 | 是 |
2.InnoDB记录存储结构
2.1 Innodb页
InnoDB lnnoDB 采取的方式是,将数据划分为若干个页 ,以页作为磁盘和内存之间交互的基本单位 . lnnoDB 中 页的大小一般为16KB 。也就是在一般情况下,一次最少从磁盘中读取 16KB 的内容到内存中,一次最少把内存中的 16KB 内容刷新到磁盘中,可以通过系统变innodb_page_size指定页大小,但我们在Mysql服务运行过程中无法热更新页大小
2.2 Innodb行格式
我们通常以行记录为单位向库表插入数据,这些记录在磁盘带上的存放形式被称为行格式,InnoDB存在4中不同类型的行格式分别为COMPACT,REDUNDANT,DYNAMIC,COMPRESSED。更改行格式可以使用语句 ALTER TABLE {TABLE_NAME}=行格式名称
2.3 Innodb数据页结构
- File Header(文件头,38字节):页的通用信息存储
- Page Header(页面头部,56字节):数据页专有的一些信息
- Infimum+Supremum(页面中的最小记录和最大记录,26字节):两条虚拟的记录注意此处的最大指的是主键最大,主键最小
- User Records(用户记录 不确定大小):用户存储的记录内容
- Free Space(空闲空间,不确定大小):页中尚未使用的空间
- Page Directory(页目录,不确定大小):页中某些记录的相对位置
- File Trailer(文件尾部,8字节):校验页是否完整
2.4记录在页中的存储
-
记录在页(Page)中的存储:
当有新的数据被插入时,会按照指定的格式存储到User records中,会先从Free Space中划分出空间并分配给User Records,当Free Space为空后,则视为当页空间用尽 -
记录在User Records中的存储结构:
- delete_flag: 用于标识该行数据是否被删除,被删除的数据记录依然会被存储在页中,暂时不会 被从磁盘上移除,因为移除这些记录会使磁盘空间不连贯,并需要重新排列其他记录,所有被删除的记录会组成一个垃圾链表,记录在这个链表中的空间称为可重用空间之后新纪录插入时,可以覆盖被删除掉的这些记录所占用的空间
- mim_rec_flag: B+树每层非子叶节点会添加该标记
- n_owned: 见页目录
- heap_no:在User_Records中数据被转换为2进制后无缝隙排列存储,mysql称之为堆,故heap_no可以理解为该记录在数据堆中的位置,其从2开始,因为mysql默认在一个页面中插入两条虚拟记录,用于标识当前页面的最大值和最小值
- next_record: 该属性非常重要,他表示从当前就的正式数据到下一条记录的真实数据的举例,如果该属性值为正数,说明当前记录的下一条在当前记录的后面,否则标识下一条记录在当前记录前面,他的本质其实是一个链表需要注意的是,下一条并不是指用户的插入顺序,而是主键值由小到大的排列
- Page Direcotory(页目录)
- 什么是目录页
由于记录在页中的存储是按照主键由小到大的顺序串成的一个单向链表,而遍历单向链表查询的效率过低,故mysql在每个页中维护了页目录这个结构其会将所有的记录数据,包括虚拟的最大值和最小值,划分为组,每个组的最后一条记录会被标识,被表示的记录的头信息中的n_owned属性表示该组共有几条记录,将每个组被标记的记录的地址偏移量(该条记录距离0字节间的距离)提取出来,按顺序存储到靠近页尾位置,就组成了page Direcotory,页目录中的地址偏移量被称为slot,每个槽占用2字节 - 插入动作对目录页的影响
初始情况下,一个数据页中只有Infimum和Supremum两条记录,他们分属于两个分组,页目录中也只存在两个slot,分别记录了这两条虚拟记录的地址偏移量,之后没插入一条记录,需要做的步骤如下:
- 从页目录中找到对应记录的主键值比待插入记录的主键值大且差值最小的slot(理论上讲slot是一个组内最大的记录的地址便宜量,我们可以很容易通过slot找到该条记录的主键值),然后把该slot的记录的n_owned值加一
- 当一个组中的数据等于8时,再插入记录则会将该分组拆分为两个分组
- 从目录页中查找记录
-
slot槽占用两个字节,各个slot无隙拼接,且记录的主键值从小到大为有序状态,所以可以使用二分法快速查找
-
找到对应slot后,通过记录的next_record属性遍历组中数据
-
Page Header(页面头部)
用于快速获取当前页的信息,包含存储记录数,FreeSpace在页面中的地址偏移量,页目录中存储了多少个槽位等,详细见mysql官网 -
File Header(文件头)
File Header通用语各种类型的页,也就是说各种类型的页都会以File Header作为第一个组成部分,他描述了一些用于与各种页的信息,比如页编码,上一页,下一页,固定占用38字节,其中较为重要的属性,FIL_PAGE_OFFSET(每页都有一个单独的页编号,如同我们的身份证号码一样,InnoDB通过页号来确定唯一的一个页),FIL_PAGE_TYPE(用于标识当前页的类型),页与页通过双向列表的形式连接 -
File Trailer(文件尾)
由8字节组成,前4个字节代表页的校验和,后4字节代码表页面最后被修改是对应的LSN的后4字节
B+树索引
1. 没有索引时进行查找
SELECT [COL] FROM [TAB] WHERE COL_NAME='XXX';
假设数据较少时,可以根据搜索条件不同分为两种情况
- 条件为主键: 通过主键定位目录页中slot的位置,找到对应的solt,遍历对应slot找到对应的值
- 条件为其他页:从Infimum开始,逐条遍历记录,比对记录中对应的值直到检索到对应符合条件的值