MySQL(表空间)
开始前先打开此图配合食用
MySQL表空间| ProcessOn免费在线作图,在线流程图,在线思维导图
InnoDB 空间文件中的页面管理
后面也会持续更新,学到新东西会在其中补充。
建议按顺序食用,欢迎批评或者交流!
缺什么东西欢迎评论!我都会及时修改的!
大部分截图和文章采用该书,谢谢这位大佬的文章,在这里真的很感谢让迷茫的我找到了很好的学习文章。我只是加上了自己的拙见。我只是记录学习没有任何抄袭意思
MySQL 是怎样运行的:从根儿上理解 MySQL - 小孩子4919 - 掘金小册
这一节有很多概念,并且很难理解,我也是花了很多时间来尽量让其变得简单。
肯定还是有些概念看不懂慢慢来吧!
打不倒我的最后都会让我变得更加强大。
前言
表空间:是一个抽象的概念对于系统表空间来说,对应着文件系统中一个或多个实际文件(idata1
,idata2
);对于每个独立表空间来说,对应着文件系统中一个名为表名.ibd
的实际文件。
一个表空间可能由操作系统层面的多个实际文件(例如 ibdata1
、 ibdata2
等)组成,但它们在逻辑上被当作一个文件,多个物理文件被视为是连接在一起的。
偏移量:这个页面 从空间开始位置的偏移量(因为对于多个文件组成的空间来说,并不一定是从文件开始位置的偏移量)。因此,0号
页面 位于偏移量为0
的位置,1号页面
位于偏移量为16384
的位置
把表空间想象成被切分为许许多多个页的池子,当我们想为某个表插入一条记录的时候,就从池子中捞出一个对应的页来把数据写进去。
- 页面类型
InnoDB
是以页为单位管理存储空间的,聚簇索引(也就是完整的表数据)和其他的二级索引都是以B+树
的形式保存到表空间的,而B+树
的节点就是数据页。
类型名称 | 十六进制 | 描述 |
---|---|---|
FIL_PAGE_TYPE_ALLOCATED | 0x0000 | 最新分配,还没使用 |
FIL_PAGE_UNDO_LOG | 0x0002 | Undo日志页 |
FIL_PAGE_INODE | 0x0003 | 段信息节点 |
FIL_PAGE_IBUF_FREE_LIST | 0x0004 | Insert Buffer空闲列表 |
FIL_PAGE_IBUF_BITMAP | 0x0005 | Insert 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 | BLOB页 |
FIL_PAGE_INDEX | 0x45BF | 索引页,也就是我们所说的数据页 |
- 页面通用部分
其中的两个部分是所有类型的页面都通用的。
任何类型的页都会包含这两个部分: File Header
:记录页面的一些通用信息File Trailer
:校验页是否完整,保证从内存到磁盘刷新时内容的一致性。
简要介绍一下File Header
的各个组成部分:
名称 | 占用空间大小 | 描述 |
---|---|---|
FIL_PAGE_SPACE_OR_CHKSUM | 4字节 | 页的校验和(checksum值) |
FIL_PAGE_OFFSET | 4字节 | 页号 |
FIL_PAGE_PREV | 4字节 | 上一个页的页号 |
FIL_PAGE_NEXT | 4字节 | 下一个页的页号 |
FIL_PAGE_TYPE | 2字节 | 该页的类型 |
FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID | 4字节 | 页属于哪个表空间 |
- 表空间中的每一个页都对应着一个页号,这个页号由
4个字节
组成,也就是32个比特位
,所以一个表空间最多可以拥有2³²个页
,如果按照页的默认大小16KB
来算,一个表空间最多支持64TB(2³² x 16KB)
的数据。表空间的第一个页的页号为0
,之后的页号分别是1,2,3...
依此类推。 - 根据
FIL_PAGE_PREV
和FIL_PAGE_NEXT
来存储上一个页和下一个页的页号。需要注意的是,这两个字段主要是为了INDEX类型的页
。一般类型的页是不使用这两个字段的。
这实际上是每个空间的大小限制,主要是由于页面号是一个
32位
的整数。
- 每个页的类型由
FIL_PAGE_TYPE
表示,比如像数据页的该字段的值就是0x45BF
。
独立表空间结构
区(extent)的概念
表空间中的页实在是太多了,为了更好的管理这些页面,提出了区(英文名:extent)
的概念。
对于16KB的页
来说,连续的64个页
就是一个区
,也就是说一个区默认占用1MB空间大小
。
不论是系统表空间还是独立表空间,都可以看成是由若干个区组成的,每256个区
被划分成一组
。
extent 0 ~ extent 255
这256个区算是第一个组,
extent 256 ~ extent 511
这256个区算是第二个组,
extent 512 ~ extent 767
这256个区算是第三个组。
第一个组(extent 0 ~ extent 255)
最开始的3个页面的类型是固定的。
FSP_HDR类型
:这个类型的页面(16KB)
是用来登记整个表空间的一些整体属性以及本组所有的区,也就是extent 0 ~ extent 255
这256个区
的属性。
其余各组(除了第一个组)最开始的2个页面(extent 256、extent 512、...)
的类型是固定的。
XDES
类型:全称是extent descriptor
,用来登记本组256个区的属性,也就是说对于在extent 256区
中的该类型(XDES)页面
存储的就是extent 256 ~ extent 511
这些区的属性。
表空间被划分为许多连续的区,每个区默认由
64个页
组成,每256个区划分为一组
,每个组的最开始的几个页面类型是固定的。
段(segment)的概念
为什么要提出区
的概念呢?表中的记录存储到页
里,页作为节点组成B+树
,这个B+树
就是索引。
表中数据少的时候用页没问题!数据变多了有待如何呢?
B+树
的每一层中的页都会形成一个双向链表
,File Header
中的FIL_PAGE_PREV
和FIL_PAGE_NEXT
字段不就是为了形成双向链表
。
向表中插入一条记录,本质上就是向该表的聚簇索引以及所有二级索引代表的B+
树的节点中插入数据。而B+树
的每一层中的页
都会形成一个双向链表
,如果是以页
为单位来分配存储空间
的话,双向链表
相邻的两个页之间的物理位置
可能离得非常远,磁盘的指针需要来回跳转这就是随机IO非常慢
。
因此,应该尽量让链表中相邻的页
的物理位置也相邻(理解成数组)
,这样才可以使用顺序I/O
。
综上所述,引入了区(extent)
的概念,在表中数据量大
的时候,为某个索引分配空间的时候就不再按照页
为单位分配了,而是按照区
为单位分配,甚至在表中的数据十分非常特别多的时候,可以一次性分配多个连续的区
。虽然会造成空间浪费,但是从性能角度看,可以消除很多的随机I/O
。
select * from student where name > 'wang' and name < 'li';
范围查询,先找到第一条name
大于'wang'
记录,随后沿着记录链表找所有name
小于'li'
记录。对B+树
叶子节点中的记录进行顺序扫描
,而如果不区分叶子节点
和非叶子节点
,统统把节点代表的页面
放到申请到的区
中的话,进行范围扫描
的效果就大打折扣了。
个人理解:假如把区
的前半部分放非叶子节点
,后半部分放叶子节点
,按照之前说法需要先从非叶子节点
找到叶子节点
,这只是二级索引
,一个表还有一个聚簇索引
那么就是两种叶子节点
和非叶子节点
,磁盘的指针就需要来回读取。
所以,B+树的叶子节点
和非叶子节点
进行了区别对待,也就是说叶子节点
有自己独有的区
,非叶子节点
也有自己独有的区
。
存放叶子节点的区的集合就算是一个段(segment)
,存放非叶子节点的区的集合也算是一个段
。也就是说一个索引会生成2个段,一个叶子节点段,一个非叶子节点段。
默认情况下一个使用InnoDB存储引擎
的表只有一个聚簇索引,一个索引会生成2个段
,而段是以区为单位申请存储空间的,一个区默认占用1M
存储空间,所以默认情况下一个只存了几条记录的小表也需要2M
的存储空间吗?介绍的其实都是很绝对的情况,一个区
被整个分配给某一个段
,即使段
的数据填不满区中所有的页面
,那余下的页面
也不能挪作他用。
根据上面情况:提出了一个碎片(fragment)区
的概念,也就是在一个碎片区
中,并不是所有的页
都是为了存储同一个段的数据
而存在的,而是碎片区
中的页
可以用于不同的目的,比如有些页用于段A,有些页用于段B,有些页甚至哪个段都不属于。
碎片区直属于表空间,并不属于任何一个段。
某个段分配存储空间的策略:
- 在刚开始向表中插入数据的时候,段是从某个碎片区以单个页面为单位来分配存储空间的。
- 当某个段已经占用了
32个碎片区页面
之后,就会以完整的区为单位来分配存储空间。
INODE Entry
为段结构,Fragment Array Entry0为碎片区页面0
依次 页面 1 、页面 2…。
段不能仅定义为是某些区的集合,更精确的应该是某些零散的页面以及一些完整的区的集合。
段是一些零散的页面以及一些完整的区的集合
区的分类
空闲的区
:现在还没有用到这个区中的任何页面。有剩余空间的碎片区
:表示碎片区中还有可用的页面。没有剩余空间的碎片区
:表示碎片区中的所有页面都被使用,没有空闲页面。附属于某个段的区
。每一个索引都可以分为叶子节点段
和非叶子节点段
,除此之外InnoDB
还会另外定义一些特殊作用的段,在这些段中的数据量很大时
将使用区
来作为基本的分配单位。
4种类型的区
也可以被称为区的4种状态(State)
状态名 | 含义 |
---|---|
FREE | 空闲的区 |
FREE_FRAG | 有剩余空间的碎片区 |
FULL_FRAG | 没有剩余空间的碎片区 |
FSEG | 附属于某个段的区 |
处于FREE
、FREE_FRAG
以及FULL_FRAG
这三种状态的区都是独立的,算是直属于表空间;而处于FSEG
状态的区是附属于某个段的。
如果把表空间比作是一个集团军,段就相当于师,区就相当于团。一般的团都是隶属于某个师的,就像是处于
FSEG
的区全都隶属于某个段,而处于FREE
、FREE_FRAG
以及FULL_FRAG
这三种状态的区却直接隶属于表空间,就像独立团(什么李云龙bushi)直接听命于军部一样。
为了方便管理这些区称为XDES Entry
的结构(全称就是Extent Descriptor Entry
),每一个区
都对应着一个XDES Entry
结构。
这个结构记录了对应的区
的一些属性。
XDES Entry
是一个40个字节
的结构,大致分为4个部分
。
Segment ID
(8字节)
每一个段都有一个唯一的编号,用ID
表示,此处的Segment ID
字段表示就是该区所在的段。List Node
(12字节)
将若干个XDES Entry
结构串联成一个链表
想定位表空间内的某一个位置的话,只需指定页号以及该位置在指定页号中的页内偏移量即可。Pre Node Page Number
和Pre Node Offset
的组合就是指向前一个XDES Entry
的指针Next Node Page Number
和Next Node Offset
的组合就是指向后一个XDES Entry
的指针。
State
(4字节)
表名区
的状态,分别是:FREE
、FREE_FRAG
、FULL_FRAG
和FSEG
。Page State Bitmap
(16字节)
这个部分共占用16个字节
,也就是128个比特位
。我们说一个区默认有64个页
,这128个比特位
被划分为64个部分
,每个部分2个比特位
,对应区中的一个页
。比如Page State Bitmap
部分的第1和第2个比特位
对应着区中的第1个页面
,第3和第4个比特位
对应着区中的第2个页面
,这两个比特位的第一个位表示对应的页是否是空闲的,第二个比特位被预留用于指示页面
是否是干净[clean]
的(干净的表示没有未刷新到磁盘的脏数据),但是这个位当前未使用,该位始终设置为1。
XDES Entry链表
初心仅仅是想提高向表插入数据的效率又不至于数据量少的表浪费空间。向表中插入数据本质上就是向表中各个索引的叶子节点段、非叶子节点段插入数据,也知道了不同的区有不同的状态。
向某个段中插入数据的过程:
- 当段中数据较少的时候,首先会查看表空间中是否有状态为
FREE_FRAG
的区,也就是找还有空闲空间的碎片区,如果找到了,那么从该区中取一些零散的页把数据插进去;否则到表空间下申请一个状态为FREE
的区,也就是空闲的区,把该区的状态变为FREE_FRAG
,然后从该新申请的区中取一些零散的页把数据插进去。之后不同的段使用零散页的时候都会从该区中取,直到该区中没有空闲空间,然后该区的状态就变成了FULL_FRAG
。 - 怎么知道表空间里的哪些区是
FREE
的,哪些区的状态是FREE_FRAG
的,哪些区是FULL_FRAG
的?这时候就是XDES Entry
中的List Node
部分发挥奇效的时候了,我们可以通过List Node
中的指针,做这么三件事:- 把状态为
FREE
的区对应的XDES Entry
结构通过List Node
来连接成一个链表,这个链表我们就称之为FREE
链表。 - 把状态为
FREE_FRAG
的区对应的XDES Entry
结构通过List Node
来连接成一个链表,这个链表我们就称之为FREE_FRAG
链表。 - 把状态为
FULL_FRAG
的区对应的XDES Entry
结构通过List Node
来连接成一个链表,这个链表我们就称之为FULL_FRAG
链表。
- 把状态为
想找一个FREE_FRAG
状态的区时,就直接把FREE_FRAG
链表的头节点拿出来,从这个节点中取一些零散的页来插入数据,当这个节点对应的区用完时,就修改一下这个节点的State
字段的值,然后从FREE_FRAG
链表中移到FULL_FRAG
链表中。同理,如果FREE_FRAG
链表中一个节点都没有,那么就直接从FREE
链表中取一个节点移动到FREE_FRAG
链表的状态,并修改该节点的STATE
字段值为FREE_FRAG
,然后从这个节点对应的区中获取零散的页就好了。
- 当段中数据已经占满了
32个零散的页
后,就直接申请完整的区来插入数据了。
怎么知道哪些区属于哪个段的呢?把状态为FSEG
的区对应的XDES Entry
结构都加入到一个链表喽?不同的段哪能共用一个区呢?想把索引a的叶子节点段和索引b的叶子节点段都存储到一个区中么?这样肯定是不可取的。 - 每个段中的区对应的
XDES Entry
结构建立了三个链表FREE
链表:同一个段中,所有页面都是空闲的区对应的XDES Entry
结构会被加入到这个链表。注意和直属于表空间的FREE
链表区别开了,此处的FREE
链表是附属于某个段(FSEG
)的。NOT_FULL
链表:同一个段中,仍有空闲空间的区对应的XDES Entry
结构会被加入到这个链表。FULL链表
:同一个段中,已经没有空闲空间的区对应的XDES Entry
结构会被加入到这个链表。
个人理解:之前不是说过区有四种状态吗?FREE
、FREE_FRAG
、FULL_FRAG
存在表空间的三种链表中,之前不是说了碎片区的概念吗?在碎片区中的页可能属于不同的段,而FSEG
是区直接分配给段,因此段里面也管理了三种链表。这样的话也能证明段是零散的页和区组成的。
每一个索引都对应两个段,每个段都会维护上述的3个链表,比如下边这个表:
CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT,c2 VARCHAR(100),c3 VARCHAR(100),PRIMARY KEY (c1),KEY idx_c2 (c2)
)ENGINE=InnoDB;
这个表t
共有两个索引,一个聚簇索引,一个二级索引idx_c2
,所以这个表共有4个段
,每个段都会维护上述3个链表
,总共是12个链表
,加上我们上边说过的直属于表空间的3个链表
,整个独立表空间共需要维护15个链表
。所以段在数据量比较大时插入数据的话,会先获取NOT_FULL
链表的头节点,直接把数据插入这个头节点对应的区中即可,如果该区的空间已经被用完,就把该节点移到FULL
链表中。
如果刚开始插入一个空表时,空间从碎片区的零碎页申请,此页面会记录在Fragment Array0
中,初始化FREE
应有空闲空间,但是NOT_NULL
和FULL
,链表的基节点是固定在INODE entry
结构中的,可以理解为空链表。
链表基节点
怎么找到某个链表的头节点或者尾节点在表空间中的位置呢?设计了一个叫List Base Node
的结构,翻译成中文就是链表的基节点。这个结构中包含了链表的头节点和尾节点的指针以及这个链表中包含了多少节点的信息。
List Length
表明该链表一共有多少节点First Node Page Number
和First Node Offset
表明该链表的头节点在表空间中的位置。Last Node Page Number
和Last Node Offset
表明该链表的尾节点在表空间中的位置。
List Base Node
结构放置在表空间中固定的位置。
综上所述,表空间是由若干个区组成的,每个区都对应一个
XDES Entry
的结构,直属于表空间的区对应的XDES Entry
结构可以分成FREE
、FREE_FRAG
和FULL_FRAG
这3个链表;每个段可以附属若干个区,每个段中的区对应的XDES Entry
结构可以分成FREE
、NOT_FULL
和FULL
这3个链表。每个链表都对应一个List Base Node
的结构,这个结构里记录了链表的头、尾节点的位置以及该链表中包含的节点数。
段的结构
段其实不对应表空间中某一个连续的物理区域,而是一个逻辑上的概念,由若干个零散的页面以及一些完整的区组成。
定义了一个INODE Entry
结构来记录一下段中的属性。
Segment ID
INODE Entry
结构对应的段的编号(ID)
。NOT_FULL_N_USED
指的是在NOT_FULL
链表中已经使用了多少个页面。计算链表中所有区段的空闲页数和,而无需遍历链表中的所有区段并对每个区中可用的空闲页求和。- 3个
List Base Node
分别为段的FREE
链表、NOT_FULL
链表、FULL
链表定义了List Base Node
,想查找某个段的某个链表的头节点和尾节点的时候,就可以直接到这个部分找到对应链表的List Base Node
。 Magic Number
INODE Entry
是否已经被初始化了(初始化的意思就是把各个字段的值都填进去了)如果这个数字是值的97937874(规定的)
,表明该INODE Entry
已经初始化,否则没有被初始化。Fragment Array Entry
每个Fragment Array Entry
结构都对应着一个零散的页面,这个结构一共4个字节
,表示一个零散页面的页号。
各类型页面详细情况
FSP_HDR
类型
首先看第一个组的第一个页面,当然也是表空间的第一个页面,页号为0
,这个页面的类型是FSP_HDR
,它存储了表空间的一些整体属性以及第一个组内256个区
的对应的XDES Entry
结构
一个完整的FSP_HDR
类型的页面大致由5个部分组成,各个部分的具体释义如下表:
名称 | 中文名 | 占用空间大小 | 简单描述 |
---|---|---|---|
File Header | 文件头部 | 38字节 | 页的一些通用信息 |
File Space Header | 表空间头部 | 112字节 | 表空间的一些整体属性信息 |
XDES Entry | 区描述信息 | 10240字节 | 存储本组256个区对应的属性信息 |
Empty Space | 尚未使用空间 | 5986字节 | 用于页结构的填充,没啥实际意义 |
File Trailer | 文件尾部 | 8字节 | 校验页是否完整 |
File Space Header部分
名称 | 占用空间大小 | 描述 |
---|---|---|
Space ID | 4字节 | 表空间的(ID) |
Not Used | 4字节 | 这4个字节未被使用,可以忽略 |
Size | 4字节 | 当前表空间占有的页面数 |
FREE Limit | 4字节 | 尚未被初始化的最小页号,大于或等于这个页号的区对应的XDES Entry结构都没有被加入FREE链表 |
Space Flags | 4字节 | 表空间的一些占用存储空间比较小的属性 |
FRAG_N_USED | 4字节 | FREE_FRAG链表中已使用的页面数量 |
List Base Node for FREE List | 16字节 | FREE链表的基节点 |
List Base Node for FREE_FRAG List | 16字节 | FREE_FRAG链表的基节点 |
List Base Node for FULL_FRAG List | 16字节 | FULL_FRAG链表的基节点 |
Next Unused Segment ID | 8字节 | 当前表空间中下一个未使用的 Segment ID |
List Base Node for SEG_INODES_FULL List | 16字节 | SEG_INODES_FULL链表的基节点 |
List Base Node for SEG_INODES_FREE List | 16字节 | SEG_INODES_FREE链表的基节点 |
List Base Node for FREE List
、List Base Node for FREE_FRAG List
、List Base Node for FULL_FRAG List
。分别是直属于表空间的FREE
链表的基节点、FREE_FRAG
链表的基节点、FULL_FRAG
链表的基节点,这三个链表的基节点在表空间的位置是固定的,就是在表空间的第一个页面(也就是FSP_HDR
类型的页面)的File Space Header
部分。FRAG_N_USED
表明在FREE_FRAG
链表中已经使用的页面数量。FREE Limit
表空间都对应着具体的磁盘文件,一开始我们创建表空间的时候对应的磁盘文件中都没有数据,需要对表空间完成一个初始化操作,包括为表空间中的区建立XDES Entry
结构,为各个段建立INODE Entry
结构,建立各种链表。一开始就为表空间申请一个特别大的空间,但是实际上有绝大部分的区是空闲的,可以选择把所有的这些空闲区对应的XDES Entry
结构加入FREE
链表,也可以选择只把一部分的空闲区加入FREE
链表,等啥时候空闲链表中的XDES Entry
结构对应的区不够使了,再把之前没有加入FREE
链表的空闲区对应的XDES Entry
结构加入FREE
链表,中心思想就是啥时候用到啥时候初始化,为表空间定义了FREE Limit
这个字段,在该字段表示的页号之前的区都被初始化了,之后的区尚未被初始化。
free limit
是所有File header
已经被初始化的所有页面中的最大页码,初始化过程中包含将页码存储在页面自身中。free limit
始终小于或等于size
。Next Unused Segment ID
表中每个索引都对应2个段
,每个段都有一个唯一的ID
,该字段表明当前表空间中最大的段ID的下一个ID,这样在创建新段的时候赋予新段一个唯一的ID值。Space Flags
标志名称 | 占用的空间(单位:bit) | 描述 |
---|---|---|
POST_ANTELOPE | 1 | 表示文件格式是否大于ANTELOPE |
ZIP_SSIZE | 4 | 表示压缩页面的大小 |
ATOMIC_BLOBS | 1 | 表示是否自动把值非常长的字段放到BLOB页里 |
PAGE_SSIZE | 4 | 页面大小 |
DATA_DIR | 1 | 表示表空间是否是从默认的数据目录中获取的 |
SHARED | 1 | 是否为共享表空间 |
TEMPORARY | 1 | 是否为临时表空间 |
ENCRYPTION | 1 | 表空间是否加密 |
UNUSED | 18 | 没有使用到的比特位 |
List Base Node for SEG_INODES_FULL List
和List Base Node for SEG_INODES_FREE List
每个段对应的INODE Entry
结构会集中存放到一个类型为INODE
的页中,如果表空间中的段特别多,则会有多个INODE Entry
结构,可能一个页放不下,这些INODE
类型的页会组成两种列表:SEG_INODES_FULL
链表,该链表中的INODE
类型的页面都已经被INODE Entry
结构填充满了,没空闲空间存放额外的INODE Entry
了。SEG_INODES_FREE
链表,该链表中的INODE
类型的页面仍有空闲空间来存放INODE Entry
结构。
XDES Entry
部分
File Space Header
部分的就是XDES Entry
部分了,XDES Entry
就是在表空间的第一个页面中保存的。知道一个XDES Entry
结构的大小是40字节
,但是一个页面的大小有限,只能存放有限个XDES Entry
结构,所以我们才把256个区
划分成一组,在每组的第一个页面中存放256个XDES Entry
结构。XDES Entry 0
就对应着extent 0
,XDES Entry 1
就对应着extent 1
… 依此类推,XDES Entry255
就对应着extent 255
。
XDES
类型
INODE
类型
第一个分组的第三个页面的类型是INODE
。为每个段设计了一个INODE Entry
结构,这个结构中记录了关于这个段的相关属性。
名称 | 中文名 | 占用空间大小 | 简单描述 |
---|---|---|---|
File Header | 文件头部 | 38字节 | 页的一些通用信息 |
List Node for INODE Page List | 通用链表节点 | 12字节 | 存储上一个INODE页面和下一个INODE页面的指针 |
INODE Entry | 段描述信息 | 16320字节 | |
Empty Space | 尚未使用空间 | 6字节 | 用于页结构的填充,没啥实际意义 |
File Trailer | 文件尾部 | 8字节 | 校验页是否完整 |
INODE Entry
部分,主要包括对应的段内零散页面的地址以及附属于该段的FREE
、NOT_FULL
和FULL
链表的基节点。每个INODE Entry
结构占用192字节
,一个页面里可以存储85个
这样的结构。
List Node for INODE Page List
因为一个表空间中可能存在超过85个段
,所以可能一个INODE
类型的页面不足以存储所有的段对应的INODE Entry
结构,所以就需要额外的INODE
类型的页面来存储这些结构。
SEG_INODES_FULL
链表:该链表中的INODE
类型的页面中已经没有空闲空间来存储额外的INODE Entry
结构了。SEG_INODES_FREE
链表:该链表中的INODE
类型的页面中还有空闲空间来存储额外的INODE Entry
结构了。
这两个链表的基节点就存储在File Space Header
里边,也就是说这两个链表的基节点的位置是固定的,所以我们可以很轻松的访问到这两个链表。以后每当我们新**创建一个段(创建索引时就会创建段)**时,都会创建一个INODE Entry
结构与之对应,存储INODE Entry
的大致过程就是这样的:
SEG_INODES_FREE
链表是否为空,如果不为空,直接从该链表中获取一个节点,也就相当于获取到一个仍有空闲空间的INODE类型
的页面,然后把该INODE Entry
结构放到该页面中。当该页面中无剩余空间时,就把该页放到SEG_INODES_FULL
链表中。- 如果
SEG_INODES_FREE
链表为空,则需要从表空间的FREE_FRAG
链表中申请一个页面,修改该页面的类型为INODE
,把该页面放到SEG_INODES_FREE
链表中,与此同时把该INODE Entry
结构放入该页面。
Segment Header 结构的运用
一个索引会产生两个段,分别是叶子节点段和非叶子节点段,而每个段都会对应一个INODE Entry
结构,怎么知道某个段对应哪个INODE Entry
结构呢?INDEX
类型的页时有一个Page Header
部分
Page Header部分
名称 | 占用空间大小 | 描述 |
---|---|---|
… | … | … |
PAGE_BTR_SEG_LEAF | 10字节 | B+树叶子段的头部信息,仅在B+树的根页定义 |
PAGE_BTR_SEG_TOP | 10字节 | B+树非叶子段的头部信息,仅在B+树的根页定义 |
PAGE_BTR_SEG_LEAF
和PAGE_BTR_SEG_TOP
都占用10个字节
,它们其实对应一个叫Segment Header
的结构
名称 | 占用字节数 | 描述 |
---|---|---|
Space ID of the INODE Entry | 4 | INODE Entry结构所在的表空间ID |
Page Number of the INODE Entry | 4 | INODE Entry结构所在的页面页号 |
Byte Offset of the INODE Ent | 2 | INODE Entry结构在该页面中的偏移量 |
PAGE_BTR_SEG_LEAF
记录着叶子节点段
对应的INODE Entry
结构的地址是哪个表空间
的哪个页面的哪个偏移量
PAGE_BTR_SEG_TOP
记录着非叶子节点段
对应的INODE Entry
结构的地址是哪个表空间
的哪个页面的哪个偏移量。
真实表空间对应的文件大小
一个新建的表对应的.ibd文件
只占用了96K
,才6个页面大小
。一开始表空间占用的空间自然是很小,因为表里边都没有数据嘛!不过别忘了这些.ibd
文件是自扩展
的,随着表中数据的增多,表空间对应的文件也逐渐增大。
系统表空间
整个MySQL进程只有一个系统表空间,在系统表空间中会额外记录一些有关整个系统信息的页面,所以会比独立表空间多出一些记录这些信息的页面。因为这个系统表空间最牛逼,相当于是表空间之首,所以它的表空间 ID(Space ID)是0。
系统表空间的整体结构
系统表空间与独立表空间的一个非常明显的不同之处就是在表空间开头有许多记录整个系统属性的页面
页号为3~7
的页面是系统表空间特有的
页号 | 页面类型 | 英文描述 | 描述 |
---|---|---|---|
3 | SYS | Insert Buffer Header | 存储Insert Buffer的头部信息 |
4 | INDEX | Insert Buffer Root | 存储Insert Buffer的根页面 |
5 | TRX_SYS | Transction System | 事务系统的相关信息 |
6 | SYS | First Rollback Segment | 第一个回滚段的页面 |
7 | SYS | Data Dictionary Header | 数据字典头部信息 |
系统表空间的extent 1
和extent 2
这两个区,也就是页号从64~191
这128个页面
被称为Doublewrite buffer
,也就是双写缓冲区
。
InnoDB数据字典
INSERT
语句向表中插入的那些记录称之为用户数据。
MySQL
先要校验一下插入语句对应的表存不存在,插入的列和表中的列是否符合,如果语法没有问题的话,还需要知道该表的聚簇索引和所有二级索引对应的根页面是哪个表空间的哪个页面,然后把记录插入对应索引的B+树
中。
还需要保存许多额外的信息,比方说:
- 某个表属于哪个表空间,表里边有多少列
- 表对应的每一个列的类型是什么
- 该表有多少索引,每个索引对应哪几个字段,该索引对应的根页面在哪个表空间的哪个页面
- 该表有哪些外键,外键对应哪个表的哪些列
- 某个表空间对应文件系统上文件路径是什么
上述这些数据并不是我们使用INSERT
语句插入的用户数据,实际上是为了更好的管理我们这些用户数据而不得已引入的一些额外数据,这些数据也称为元数据。
InnoDB
存储引擎特意定义了一些列的内部系统表(internal system table
)来记录这些这些元数据:
元数据的就是这个表有几个字段,每个字段是字符还是数字,这个表谁能访问,谁不能访问。
表名 | 描述 |
---|---|
SYS_TABLES | 整个InnoDB存储引擎中所有的表的信息 |
SYS_COLUMNS | 整个InnoDB存储引擎中所有的列的信息 |
SYS_INDEXES | 整个InnoDB存储引擎中所有的索引的信息 |
SYS_FIELDS | 整个InnoDB存储引擎中所有的索引对应的列的信息 |
SYS_FOREIGN | 整个InnoDB存储引擎中所有的外键的信息 |
SYS_FOREIGN_COLS | 整个InnoDB存储引擎中所有的外键对应列的信息 |
SYS_TABLESPACES | 整个InnoDB存储引擎中所有的表空间信息 |
SYS_DATAFILES | 整个InnoDB存储引擎中所有的表空间对应文件系统的文件路径信息 |
SYS_VIRTUAL | 整个InnoDB存储引擎中所有的虚拟生成列的信息 |
这些系统表也被称为数据字典,它们都是以B+树
的形式保存在系统表空间的某些页面中,其中SYS_TABLES
、SYS_COLUMNS
、SYS_INDEXES
、SYS_FIELDS
这四个表尤其重要,称之为基本系统表(basic system tables)
SYS_TABLES表
列名 | 描述 |
---|---|
NAME | 表的名称 |
ID | InnoDB存储引擎中每个表都有一个唯一的ID |
TYPE | 表的类型,记录了一些文件格式、行格式、压缩等信息 |
MIX_ID | 已过时,忽略 |
MIX_LEN | 表的一些额外的属性 |
CLUSTER_ID | 未使用,忽略 |
SPACE | 该表所属表空间的ID |
#这是MySQL5.7版本的
select * from INNODB_SYS_TABLES;
这个SYS_TABLES
表有两个索引:
- 以
NAME
列为主键的聚簇索引 - 以
ID
列建立的二级索引
#MySQL 5.7
mysql> USE information_schema;
Database changedmysql> SHOW TABLES LIKE 'INNODB_SYS%';
+--------------------------------------------+
| Tables_in_information_schema (INNODB_SYS%) |
+--------------------------------------------+
| INNODB_SYS_DATAFILES |
....
+--------------------------------------------+
10 rows in set (0.00 sec)注意: 用户不能直接访问 InnoDB 的内部系统表,除非直接去解析系统表空间对应文件系统上的文件。
不过考虑到查看这些表的内容可能有助于分析问题,所以在系统数据库 information_schema
中提供了一些以 INNODB_SYS 开头的表:#MySQL 9.0
mysql> USE information_schema;
Database changedmysql> SHOW TABLES LIKE 'INNODB%';
+----------------------------------------+
| Tables_in_information_schema (INNODB%) |
+----------------------------------------+
| INNODB_BUFFER_PAGE |
.....
+----------------------------------------+
31 rows in set (0.01 sec)
SYS_COLUMNS表
列名 | 描述 |
---|---|
TABLE_ID | 该列所属表对应的ID |
POS | 该列在表中是第几列 |
NAME | 该列的名称 |
MTYPE | main data type,主数据类型,就是那堆INT、CHAR、VARCHAR、FLOAT、DOUBLE之类 |
PRTYPE | precise type,精确数据类型,就是修饰主数据类型,比如是否允许NULL值,是否允许负数 |
LEN | 该列最多占用存储空间的字节数 |
PREC | 该列的精度,不过这列貌似都没有使用,默认值都是0 |
这个SYS_COLUMNS
表只有一个聚集索引:
- 以
(TABLE_ID, POS)
列为主键的聚簇索引
SYS_INDEXES表
列名 | 描述 |
---|---|
TABLE_ID | 该索引所属表对应的ID |
ID | InnoDB存储引擎中每个索引都有一个唯一的ID |
NAME | 该索引的名称 |
N_FIELDS | 该索引包含列的个数 |
TYPE | 该索引的类型,比如聚簇索引、唯一索引、更改缓冲区的索引、全文索引、普通的二级索引等等各种类型 |
SPACE | 该索引根页面所在的表空间ID |
PAGE_NO | 该索引根页面所在的页面号 |
MERGE_THRESHOLD | 如果页面中的记录被删除到某个比例,就把该页面和相邻页面合并,这个值就是这个比例 |
这个SYS_INDEXES
表只有一个聚集索引:
- 以
(TABLE_ID, ID)
列为主键的聚簇索引
SYS_FIELDS表
列名 | 描述 |
---|---|
INDEX_ID | 该索引列所属的索引的ID |
POS | 该索引列在某个索引中是第几列 |
COL_NAME | 该索引列的名称 |
这个SYS_INDEXES
表只有一个聚集索引:
- 以
(INDEX_ID, POS)
列为主键的聚簇索引
Data Dictionary Header页面
只要有了上述4个
基本系统表,也就意味着可以获取其他系统表以及用户定义的表的所有元数据。SYS_TABLESPACES
这个系统表里存储了哪些表空间以及表空间对应的属性。
-
到
SYS_TABLES
表中根据表名定位到具体的记录,就可以获取到SYS_TABLESPACES
表的TABLE_ID
-
使用这个
TABLE_ID
到SYS_COLUMNS
表中就可以获取到属于该表的所有列的信息。
-
使用这个
TABLE_ID
还可以到SYS_INDEXES
表中获取所有的索引的信息,索引的信息中包括对应的INDEX_ID
,还记录着该索引对应的B+树
根页面是哪个表空间的哪个页面。
-
使用
INDEX_ID
就可以到SYS_FIELDS
表中获取所有索引列的信息。
那这4个表的元数据去哪里获取呢?
拿出一个固定的页面来记录这4个表
的聚簇索引和二级索引对应的B+树
位置,这个页面就是页号为7
的页面,类型为SYS
,记录了Data Dictionary Header
,也就是数据字典的头部信息。记录了Data Dictionary Header
,也就是数据字典的头部信息。
名称 | 中文名 | 占用空间大小 | 简单描述 |
---|---|---|---|
File Header | SYS | Insert Buffer Header | 存储Insert Buffer的头部信息 |
Data Dictionary Header | INDEX | Insert Buffer Root | 存储Insert Buffer的根页面 |
Segment Header | TRX_SYS | Transction System | 事务系统的相关信息 |
Empty Space | SYS | First Rollback Segment | 第一个回滚段的页面 |
File Trailer | SYS | Data Dictionary Header | 数据字典头部信息 |
这个页面有Segment Header
部分,这些有关数据字典的信息当成一个段来分配存储空间,我们就姑且称之为数据字典段吧。需要记录的数据字典信息非常少(可以看到Data Dictionary Header
部分仅占用了56字节
),所以该段只有一个碎片页,也就是页号为7
的这个页
。
-
Max Row ID
:如果我们不显式的为表定义主键,而且表中也没有UNIQUE索引
,那么InnoDB存储引擎
会默认为我们生成一个名为row_id
的列作为主键。因为它是主键,所以每条记录的row_id列
的值不能重复。原则上只要一个表中的row_id列
不重复就可以了,也就是说表a
和表b
拥有一样的row_id列
也没啥关系,只提供了这个Max Row ID
字段,不论哪个拥有row_id列
的表插入一条记录时,该记录的row_id列
的值就是Max Row ID
对应的值,然后再把Max Row ID
对应的值加1
,也就是说这个Max Row ID
是全局共享的。 -
Max Table ID
:InnoDB存储引擎
中的所有的表都对应一个唯一的ID
,每次新建一个表时,就会把本字段的值作为该表的ID
,然后自增本字段的值。 -
Max Index ID
:InnoDB存储引擎
中的所有的索引都对应一个唯一的ID
,每次新建一个索引时,就会把本字段的值作为该索引的ID
,然后自增本字段的值。 -
Max Space ID
:InnoDB存储引擎
中的所有的表空间都对应一个唯一的ID
,每次新建一个表空间时,就会把本字段的值作为该表空间的ID
,然后自增本字段的值。 -
Root of SYS_TABLES clust index
:本字段代表SYS_TABLES
表聚簇索引的根页面的页号。 -
Root of SYS_TABLE_IDS sec index
:本字段代表SYS_TABLES
表为ID列
建立的二级索引的根页面的页号。 -
Root of SYS_COLUMNS clust index
:本字段代表SYS_COLUMNS
表聚簇索引的根页面的页号。 -
Root of SYS_INDEXES clust index
本字段代表SYS_INDEXES
表聚簇索引的根页面的页号。 -
Root of SYS_FIELDS clust index
:本字段代表SYS_FIELDS
表聚簇索引的根页面的页号。
之前说过了这四个重要的表,有五个索引而索引的根页面是固定的,因此我们通过索引根页面就可以遍历到整棵B+树
。
小结
先看一张大概总结的图
插入一条数据流程:
MySQL插入数据
总结
所有结论都需要反复测试!如果有错误欢迎指正!一起努力!
如果喜欢的话,请点个赞吧就算鼓励我一下。
相关文章:
MySQL(表空间)
开始前先打开此图配合食用 MySQL表空间| ProcessOn免费在线作图,在线流程图,在线思维导图 InnoDB 空间文件中的页面管理 后面也会持续更新,学到新东西会在其中补充。 建议按顺序食用,欢迎批评或者交流! 缺什么东西欢迎评论!我都…...
智能化加速标准和协议的更新并推动验证IP(VIP)在芯片设计中的更广泛应用
作者:Karthik Gopal, SmartDV Technologies亚洲区总经理 智权半导体科技(厦门)有限公司总经理 随着AI技术向边缘和端侧设备广泛渗透,芯片设计师不仅需要考虑在其设计中引入加速器,也在考虑采用速度更快和带宽更高的总…...
Chrome远程桌面无法连接怎么解决?
Chrome远程桌面连接已停止工作 Chrome远程桌面是一款极为便捷的浏览器插件,能够帮助用户将自己的计算机连接到其他设备,无论是手机、平板电脑还是其他电脑。然而,在实际使用中,许多用户可能会面临各种各样的问题,比如…...
springcloud alibaba 五大组件
Spring Cloud Alibaba是Spring Cloud的一个子项目,致力于为构建分布式应用提供一站式解决方案。它基于阿里巴巴的底层Java开源框架,主要包含以下五大核心组件: 1. Nacos(服务注册与配置中心) 功能:Nacos提…...
es 3期 第25节-运用Rollup减少数据存储
#### 1.Elasticsearch是数据库,不是普通的Java应用程序,传统数据库需要的硬件资源同样需要,提升性能最有效的就是升级硬件。 #### 2.Elasticsearch是文档型数据库,不是关系型数据库,不具备严格的ACID事务特性ÿ…...
理解深度学习pytorch框架中的线性层
文章目录 1. 数学角度: y W x b \displaystyle y W\,x b yWxb示例 2. 编程实现角度: y x W T b \displaystyle y x\,W^T b yxWTb3. 常见错误与易混点解析4. 小结参考链接 在神经网络或机器学习的线性层(Linear Layer / Fully Connect…...
“上门按摩” 小程序开发项目:基于 SOP 的全流程管理
在竞争激烈的生活服务市场,“上门按摩” 服务需求日益增长。为满足这一需求,我们启动了 O2O 模式的 “上门按摩” 小程序开发项目,该项目涵盖客户端、系统管理端、技师端。以下将通过各类 SOP 对项目进行全面管理,确保项目顺利推进。 一、项目启动 SOP:5W2H 分析法 What(…...
【xcode 16.2】升级xcode后mac端flutter版的sentry报错
sentry_flutter 7.11.0 报错 3 errors in SentryCrashMonitor_CPPException with the errors No type named terminate_handler in namespace std (line 60) and No member named set_terminate in namespace std 替换sentry_flutter版本为: 8.3.0 从而保证oc的…...
Unity自学之旅05
Unity自学之旅05 Unity学习之旅⑤📝 AI基础与敌人行为🥊 AI导航理论知识(基础)开始实践 🎃 敌人游戏机制追踪玩家攻击玩家子弹碰撞完善游戏失败条件 🤗 总结归纳 Unity学习之旅⑤ 📝 AI基础与敌…...
LINUX下设置分离状态(Detached State)和未设置分离状态的主要区别在于线程资源的管理方式和线程的生命周期。以下是两种状态的对比:
1. 设置分离状态(Detached State) 资源管理: 线程终止时,系统会自动释放与线程相关的所有资源(如线程栈、线程控制块)。不需要其他线程显式回收(pthread_join)。 线程生命周期&…...
软考信安26~大数据安全需求分析与安全保护工程
1、大数据安全威胁与需求分析 1.1、大数据相关概念发展 大数据是指非传统的数据处理工具的数据集,具有海量的数据规模、快速的数据流转、多样的数据类型和价值密度低等特征。 大数据的种类和来源非常多,包括结构化、半结构化和非结构化数据。 1.2、大数据安全威胁分析 (…...
Alibaba Spring Cloud 一 核心组件、特性
Alibaba Spring Cloud 是 Alibaba 基于 Spring Cloud 的分布式微服务解决方案,提供了一套高性能、高可靠的微服务开发和运维工具。它扩展了 Spring Cloud 的功能,并优化了许多在生产环境中的实践场景,例如服务发现、配置管理、熔断限流等。 …...
通过脚本申请免费SSL证书(泛解析SSL证书)
参考来源 1.https://github.com/acmesh-official/acme.sh/wiki/%E8%AF%B4%E6%98%8E 2.https://github.com/acmesh-official/acme.sh/wiki/dns-manual-mode 3.https://github.com/acmesh-official/acme.sh/wiki/dnsapi 安装 acme.sh 配置账号 配置默认CA 安装依赖 # Cento…...
基于相机内参推导的透视投影矩阵
基于相机内参推导透视投影矩阵(splatam): M c a m [ 2 ⋅ f x w 0.0 ( w − 2 ⋅ c x ) w 0.0 0.0 2 ⋅ f y h ( h − 2 ⋅ c y ) h 0.0 0 0 f a r n e a r n e a r − f a r 2 f a r ⋅ n e a r n e a r − f a r 0.0 0.0 − 1.0 0.0 ] M_…...
代码随想录算法训练营day34
代码随想录算法训练营 —day34 文章目录 代码随想录算法训练营前言一、62.不同路径动态规划动态规划空间优化 二、63. 不同路径 II动态规划动态规划优化空间版 三、343. 整数拆分动态规划贪心算法 96.不同的二叉搜索树总结 前言 今天是算法营的第34天,希望自己能够…...
Orgill EDI需求分析
Orgill 是一家位于美国的家族企业,主要为五金零售商、建材供应商及相关行业提供全面的分销服务和支持,覆盖范围遍及全球。 EDI需求分析 EDI全称Electronic Data Interchange,中文名称是电子数据交换,也被称为“无纸化贸易”。EDI…...
好用的js工具类
格式化相关 // 数字每三位增加一个逗号 function toThousands(num) {if (num) {return num.toString().replace(/\d/, function(n) {// 先提取整数部分return n.replace(/(\d)(?(\d{3})$)/g, function($1) {return $1 ,})})} else {return 0} }//输出10,000 toThousands(10…...
C++ —— 基于范围的 for 循环
C —— 基于范围的 for 循环 语法push_back() 与 emplace_back() 的区别**emplace_back()** 示例代码如下:**push_back()** 示例代码如下: 容器中的元素是结构体和类 语法 C11中引入了基于范围的for循环,语法如下: for (迭代的变…...
15-spring整合mybatis方式一
spring整合mybatis 方式一【重要】 步骤: 1.导入相关jar包 junit mybatis mysql数据库 spring相关的 aop织入 mybatis-spring 【new】 junit junit 4.12 mysql mysql-connector-java 8.0.23 org.mybatis mybatis 3.5.2 org.springframework spring-webmvc 5…...
数据结构:二叉树—面试题(一)
目录 1、相同的树 2、另一棵树的子树 3、翻转二叉树 4、平衡二叉树 5、对称二叉树 6、二叉树遍历 7、二叉树的分层遍历 1、相同的树 习题链接https://leetcode.cn/problems/same-tree/description/https://leetcode.cn/problems/same-tree/description/ 描述:…...
GPU算力平台|在GPU算力平台部署可图大模型Kolors的应用实战教程
文章目录 一、GPU算力服务平台GPU算力服务平台的概述 二、平台账号注册流程可图大模型Kolors的应用实战教程可图大模型的介绍可图大模型的应用场景可图大模型Kolors的部署步骤 一、GPU算力服务平台 GPU算力服务平台的概述 蓝耘GPU算力平台专为高性能计算设计,广泛…...
Linux探秘坊-------4.进度条小程序
1.缓冲区 #include <stdio.h> int main() {printf("hello bite!");sleep(2);return 0; }执行此代码后,会 先停顿两秒,再打印出hello bite,但是明明打印在sleep前面,为什么会后打印呢? 因为ÿ…...
Ansys Motor-CAD:IPM 电机实验室 - 扭矩速度曲线
各位电动机迷们,大家好: 在本博客中,我讨论了如何使用 Ansys Motor-CAD 通过 LAB 模块获取扭矩速度曲线。使用每安培最大扭矩电机控制策略,并涵盖恒定扭矩区域和恒定功率、磁通减弱区域。分析了高转子速度如何影响功率输出。 模型…...
关于事件捕获和事件冒泡的理解
我一直对事件捕获和事件冒泡是挺困惑的,好像理解了,但又感觉哪里不对。这篇文章打算深入探讨一些细节性的问题,更好的理解事件捕获和事件冒泡。 当我们点击的时候,浏览器的默认行为是怎么样的? 搞清楚这个非常的重要…...
如何使用HASH创建低交互式蜜罐系统
关于HASH HASH是一个用于创建和启动低交互蜜罐的框架,可以帮助广大研究人员轻松创建HTTP无关的低交互式软件蜜罐。 HASH 的主要理念是易于配置,能够灵活地模拟在 HTTP/HTTPs 上运行的任何软件。尽可能减少占用空间,避免被检测为蜜罐。 功能…...
vue3+vite+ts安装wangeditor富文本编辑器
需求: 实现粘贴,上传图片时本地渲染但并不实现上传功能,工具栏移除不需要的工具 安装方法看官网 安装 | wangEditor 封装子组件 wangEditor.vue <template><div><div style"border: 1px solid #ccc; margin-top: 10px"><Toolbar:editor&qu…...
PostIn教程-安装配置
PostIn是一款国产开源免费的接口管理工具,包含项目管理、接口调试、接口文档设计、接口数据MOCK等模块,支持常见的HTTP协议、websocket协议等,支持免登陆本地接口调试,同时可以对项目进行灵活的成员权限、消息通知管理等。 1、服务…...
SpringBoot读取配置优先级顺序是什么?
Spring Boot外部化配置详解 目录 引言Spring Boot外部化配置概述配置加载优先级配置加载顺序详解实际案例总结 引言 Spring Boot因其“开箱即用”的特性,极大地简化了Java应用的开发和部署过程。它通过外部化配置机制,允许开发者根据不同的环境&#x…...
群晖docker获取私有化镜像http: server gave HTTP response to HTTPS client].
群晖docker获取私有化镜像提示http: server gave HTTP response to HTTPS clien 问题描述 层级时间用户事件Information2023/07/08 12:47:45cxlogeAdd image from xx.xx.31.240:1923/go-gitea/gitea:1.19.3Error2023/07/08 12:47:48cxlogeFailed to pull image [Get "http…...
MySQL8【学习笔记】
第一章前提须知 1.1 需要学什么 Dbeaver 的基本使用SQL 语句:最重要的就是查询(在实战的时候,你会发现我们做的绝大部分工作就是 “查询”)MySQL 存储过程(利用数据库底层提供的语言,去进行业务逻辑的封装…...
汇编实验·子程序设计
一、实验目的: 1.掌握汇编中子程序编写方法 2.掌握程序传递参数的基本方法,返回值的方法。 3.掌握理解子程序(函数)调用的过程 二、实验内容 1.编写汇编语言子程序,实现C表达式SUM=X+Y的功能,具体要求: 1)函数的参数传递采用寄存器实现 2)函数的参数传递采用堆栈…...
EDI安全:2025年数据保护与隐私威胁应对策略
在数字化转型的浪潮中,电子数据交换(EDI)已成为企业间信息传递的核心基础设施。然而,随着数据规模的指数级增长和网络威胁的日益复杂化,EDI安全正面临前所未有的挑战。展望2025年,企业如何构建一套全面、高…...
Cloudpods是一个开源的Golang实现的云原生的融合多云/混合云的云平台,也就是一个“云上之云”。
Cloudpods是一个开源的Golang实现的云原生的融合多云/混合云的云平台,也就是一个“云上之云”。Cloudpods不仅可以管理本地的虚拟机和物理机资源,还可以管理多个云平台和云账号。Cloudpods隐藏了这些异构基础设施资源的数据模型和API的差异,对…...
C++小病毒-1.0勒索
内容供学习使用,不得转卖,代码复制后请1小时内删除,此代码会危害计算机安全,谨慎操作 在C20环境下,并在虚拟机里运行此代码! #include <iostream> #include <windows.h> #include <shellapi.h> #include <stdio.h> #include <fstream> #include…...
MySQL入门(数据库、数据表、数据、字段的操作以及查询相关sql语法)
天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。…...
AIGC视频扩散模型新星:Video 版本的SD模型
大家好,这里是好评笔记,公主号:Goodnote,专栏文章私信限时Free。本文详细介绍慕尼黑大学携手 NVIDIA 等共同推出视频生成模型 Video LDMs。NVIDIA 在 AI 领域的卓越成就家喻户晓,而慕尼黑大学同样不容小觑,…...
08-ArcGIS For JavaScript-通过Mesh绘制几何体(Cylinder,Circle,Box,Pyramid)
目录 概述代码实现1、Mesh.createBox2、createPyramid3、Mesh.createSphere4、Mesh.createCylinder 完整代码 概述 对于三维场景而言,二位的点、线、面,三维的圆、立方体、圆柱等都是比较常见的三维对象,在ArcGIS For JavaScript中我们知道点…...
在 Go 语言中如何高效地处理集合
文章精选推荐 1 JetBrains Ai assistant 编程工具让你的工作效率翻倍 2 Extra Icons:JetBrains IDE的图标增强神器 3 IDEA插件推荐-SequenceDiagram,自动生成时序图 4 BashSupport Pro 这个ides插件主要是用来干嘛的 ? 5 IDEA必装的插件&…...
Python的进程和线程
ref 讲个故事先 这就像一个舞台(CPU核心), 要供多个剧组演出多个剧目(进程), 剧目中有多个各自独立的角色(线程),有跑龙套的,有主角,第一…...
基于单片机的智能台灯设计
摘要: 方向和亮度,采用的是手动调节。而对于儿童来说,他们通常不知道如何调整以及调整到何种程度。本文设计了一款智能台灯,当有人的 台灯是用于阅读学习而设计使用的灯,一般台灯用的灯泡是白炽灯、节能灯泡以及市面上流行的护眼台灯,可以调节高度、光照的时候,可以根据…...
vue3案例:筛选部门、选择人员案例组件
可以控制可以选多人,或者只能选单人可以做部门筛选再选人,没有部门情景,直接显示全部人员,有输入框可以搜索人员 ✨一、实现功能 需求: 可以灵活控制,多选或者单选人员配合部门进行部门下的人员筛选 详细…...
Spring MVC:综合练习 - 深刻理解前后端交互过程
目录 1. Lombok 1.1 引入 lombok 依赖 1.1.1 通过 Maven 仓库引 lombok 依赖 1.1.2 通过插件引入 lombok 依赖 1.2 Data 1.3 其他注解 2. 接口文档 2.1 接口(api) 2.2 接口文档 3. 综合练习 - 加法计算器 3.1 定义接口文档 3.2 准备工作 - 前端代码 3.3 后端代码 …...
Debian常用命令
以下是完整的 Linux 命令大全,适用于 Debian、Ubuntu 及其衍生系统,涵盖系统管理、文件操作、磁盘管理、用户管理、网络调试、安全、进程管理等多个方面。 目录 基本命令关机与重启文件和目录管理文件搜索挂载文件系统磁盘空间管理用户和群组管理文件和…...
【FFmpeg】FLV 格式分析 ③ ( Tag Body 数据块体结构 - Vedio Data 视频数据 )
文章目录 一、Tag Body 数据块体结构 - Video Data 视频数据1、Vedio Data 视频数据 类型标识2、Vedio Data 视频数据 结构分析3、Composition Time Offset 字段涉及的时间计算4、AVC Packet Type 字段说明① AVC Sequence Header 类型② AVC NALU 类型③ AVC End of Sequence …...
开源鸿蒙开发者社区记录
lava鸿蒙社区可提问 Laval社区 开源鸿蒙项目 OpenHarmony 开源鸿蒙开发者论坛 OpenHarmony 开源鸿蒙开发者论坛...
MinIO的安装与使用
目录 1、安装MinIO 1.1 下载 MinIO 可执行文件 1.2 检查 MinIO 是否安装成功 1.3 设置数据存储目录 1.4 配置环境变量(可选) 1.5 编写启动的脚本 1.6 开放端口 1.7 访问 2、项目实战 2.1 引入依赖 2.2 配置yml文件 2.3 编写Minio配置类 2.4…...
【分布式日志篇】从工具选型到实战部署:全面解析日志采集与管理路径
网罗开发 (小红书、快手、视频号同名) 大家好,我是 展菲,目前在上市企业从事人工智能项目研发管理工作,平时热衷于分享各种编程领域的软硬技能知识以及前沿技术,包括iOS、前端、Harmony OS、Java、Python等…...
Spring Boot/MVC
一、Spring Boot的创建 1.Spring Boot简化Spring程序的开发,使用注解和配置的方式开发 springboot内置了tomact服务器 tomact:web服务器,默认端口号8080,所以访问程序使用8080 src/main/java:Java源代码 src/main/resource:静态资源或配置文件,存放前端代码(js,css,html) s…...
uni-app连接EventSource
前言 uniapp默认是不支持event-source,这里是借助renderjs进行SSE连接 正文 引入event-source-polyfill 这里演示的是直接将代码下载到本地进行引入 下载地址 把里面的eventsource.min.js文件放到项目中的static文件夹 项目封装event-source.vue组件 <templ…...
[SCTF2019]babyre
[SCTF2019]babyre 一、查壳 无壳,64位 二、IDA分析 1.没有main,那就shifef12 点击: 再进: 都是花指令,所以要先解决花指令 三、解决花指令,得到完整的 main 往上面翻,注意看爆红的&#x…...