• MySQL实现的一点总结(二)


    数据目录:
    Show variables like ‘datadir’;
    数据目录下,用户创建的database对应一个同名的文件夹;
    文件夹中有一个db.opt文件,包含db的一些属性,如字符集、比较规则等;
    还有一个表名.frm文件,用来存储表结构(名称、列、数据类型、约束、索引等)
    表空间:
    对于InnoDB,有系统表空间和独立表空间(5.66之后):
    系统表空间:ibdata,只有一份,12MB,自扩展,可自定义名称、个数、大小;
    独立表空间:表名.ibd,存本表的数据;
    可配置每张表使用系统还是独立表空间:alter table xx table space innodb_system/innodb_file_per_table;
    对于MyIsAm:每个表分为xx.frm(结构文件)、xx.MYD(数据文件)、xx.MYI(索引文件)——相对应的,InnoDB中的数据是放在聚簇索引(主键)一起的;
    文件名中的特殊字符映射成@+编码值,文件名和文件长度都受文件系统制约;
    MySQL的系统数据库:mysql(记录账户、权限、存储过程、事件、日志等);
    Information_schema(所有其他database信息:表、视图、触发器、列、索引等元数据);
    Performance_schema(服务器状态信息、性能监控、执行语句所花时间、内存等);

    在文件中的存储结构:
    Fileheader结构(本页信息):
    checksum、
    offset(本页号)、
    prev(上页号)、
    next(下页号)、
    LSN(日志号)、
    type(页类型)、
    space_id(表空间ID)、
    flushLSN
    数据页(索引页)根据上下页号形成双链表,用于在B树的同一层顺序查找;
    MySQL以页(16K)为单位,每64页一个区(1M),每256个区一个组(256M);
    分组可能只是为了便于管理,
    比如第一组的前三个页面做特殊用途(第一页类型FSR_HDR,记录整个表空间的属性和本组所有区的属性;第二页类型IBUFF_BITMAP,是关于change buffer的;第三页类型INODE,用来存INODE Entry),
    之后的每组前俩页面是特殊用途(第一页类型XDES,记录本组所有区的属性;第二页类型IBUFF_BITMAP);
    分区是有实际作用的,每个区是物理上连续的64个页,目的是减少磁盘I/O,表示索引的B+树的所有非叶子节点构成一个段,所有叶子节点构成另一个段;即对于InnoDB的聚簇索引来说,会生成俩段,每个段以区为单位分配空间,——but这样对于小表来说很浪费,所以另外搞一个碎片区(全局):开始插数据的时候从碎片区以页为单位拿空间,,当某个段占用了32个碎片页之后,便有资格以区为单位拿空间(之前的碎片页并不会迁移到新的空间),——so,准确来讲,段是由一些碎片页(32)和一些完整的区构成的;
    区类型(状态):空闲区(free)、有剩余碎片区(free_frag)、满碎片区(full_frag)、属于某个段的区(fseg);前三种不属于任何段,而直属于表空间(独立团),根据占用情况分成上面那三种类型;
    XDES_Entry:记录一个区的一些属性
    Segment ID:该区所属的段;
    List node:包含prev page、prev offset、next page、next offset,即前后节点所在页号和偏移,从而形成双链;
    State:有free、free_frag、full_frag、fseg四种状态(对应上面四种区类型);
    Bitmap:表示本区的每个页面是否空闲(位图)
    有了代表区的这个结构,就可以把区归类到不同的链表上:首先free、free_frag、full_frag这三种状态,通过list node连成三个链表,当段需要空间时,在只能要碎片页时就去free_frag链表头代表的区中拿页面,当此区没有空闲页时,就挂到full_frag链表上,当free_frag空了时,从free链表上取节点——怎么感觉free_frag只需要一个节点就够了,链表是啥情况?
    当某段已经拿了32个碎片页后,开始为其分派完整的区(fseg状态)——应该是从free链表拿的?属于某段的区同样有free、not_full、full三种状态,做成三个链表——为啥会有free状态?即使有,一个节点也就够了吧,链表又是什么情况?
    So,聚簇索引维护两个段,每个段维护3个链表。
    Then,使用链表基节点list base node标识以上每一条链表(基节点包含length、first page&offset、last page&offset,即节点数和头尾指针),然后存在表空间的固定位置。

    INODE Entry:表示段信息的结构——上面说过,第一组的第三页(类型INODE)用来存所有的INODE Entry
    Segment ID:本段的ID;
    Not full n used:not full 中已使用的页面数;
    List node free、list node not full、list node full:段的三个区链表;
    Magic number:本段是否初始化;
    Fragment array:32个碎片页的页号
    可见此结构主要管理了自己所拥有的页面。

  • 相关阅读:
    那些一门心思研究自动化测试的人,最后都怎样了?
    使用容器方式创建firecracker虚拟机
    Kotlin基本语法
    华为云 云证书(SSL)管理服务
    vue中引入字体
    TOPDON获评2023年度“汽车后市场科技创新企业”,研发实力被认可
    Java语法基础
    怎么把图片压缩小一点?4个简单的压缩办法
    基础IO —— Linux
    Android SurfaceFlinger导读(04)理解BufferQueue
  • 原文地址:https://blog.csdn.net/weixin_40852534/article/details/126377016