众所周知,想要清晰的了解一款软件的运作原理,最重要的就是要了解它的物理结构、内存结构和内部线程运行分工。下面让我们一起来看看innodb的物理表空间的结构。
表空间又分为公共表空间“ibdata”文件和表的私有表空间“表名.ibd”文件,在私有表空间里存放的数据只有表数据、索引、和插入缓冲Bitmap页(描述插入缓冲的页的信息的页,一个插入缓冲位图页可以追踪16384个插入缓冲页),其它信息如回滚日志、插入缓冲索引页、二次写缓冲等则储存在公共表空间里。
表空间的结构划分为:段、区(1M)、页(默认16K,压缩页有8K、4K等。也有称为块),页为缓存和磁盘的最小交互单位。下图为段、区、页的结构:
段
根据存储的数据类型不同,段又可分为数据段、索引段、回滚段等。需要注意的是由于innodb表是B+树索引组织的,索引即数据、数据即索引(B+树相关下个篇张具体聊,现在现有个概念就行),因此数据段存放的是B+树的叶子节点数据页和索引页,而索引段存储的并不是索引页,而是B+树的非叶子节点。在innodb,段的管理是由innodb自身完成,我们对它稍作了解即可。
区
区由连续的页组成,正常情况下大小为1M,为了写入的时候更有可能的顺序写,一般innodb申请区空间的时候会一次性申请四五个区。默认情况下页的大小为16k,即一个区一般情况下由64个页。innodb1.0.x后引入了压缩页,出现了2k、4k、8k的页,此时每个区对应的页数为512、256、128,innodb1.2.x后引入了页大小参数innodb_page_size,此后非压缩也也可以为4k、8k。
为了节省磁盘开销,默认每个段开始时会先用32个页大小的碎片页来存放数据,而后才会64个连续页的申请空间。
页
页时磁盘管理的最小单位,也是缓冲和磁盘交互的最小单位,有些地方也称为块。常见的页类型有:数据页、undo页、系统页、事务数据页、插入缓冲位图页、插入缓冲空闲列表页、未压缩的二进制大对象页、压缩的二进制大对象页。
行
innodb是面向行的存储引擎(row-oriented)。innodb的行结构除了业务字段外,还有三个隐藏字段:rowid(默认和主键值相同,没有主键的话则自动生成),最后更新此数据的事务ID,回滚日志指针(在聊多版本并发控制的时候细聊)。
innodb对行的记录格式,也进行过多次的升级。可以输入命令行show table status like '表名';来看你的表的行记录格式,5.7版本的MySQL默认是Dynamic。
innodb1.0.x之前,行记录格式只有Redundant和Compact,Redundant是为了兼容旧版的页格式而出现的记录格式,Compact对比Redundant,多了NULL标志位,即相对NULL比较多的行Compact格式存储的数据会比较紧凑。
innodb1.0.x版本后引入了Compressed行记录格式和Dynamic行记录格式,统称Barracuda文件格式,旧版的Redundant和Compact称为Antelope文件格式。新的格式对于blob类型的数据采用完全行溢出的存放方式:旧版的在行内也会存储768个前缀字节的blob的数据,超出部分存放到大对象页。新版的不管超不超出直接存放到大对象页。
分区
最后聊一聊大家可能会关心的表分区,对于MySQL分区在MySQL层面完成。分区的原理即将一个表或索引拆分为多个更小、更可管理的部分,而对访问数据库的应用来说,在逻辑上只有一个表。MySQL只支持水平分区:Range分区、List分区、Hash分区、Key分区、子分区(在分区基础上再进行分区),本质上都是根据主键(没有主键第一个候选码也行,没有候选码rowid也行)将行数据分布在不同的分区,直观看来就是一个表会出现多个.ibd文件。
对于innodb来说,我个人理解,数据表还是不如不分区的好。假设一个表有1000w数据,对于主键查询来说,拆分为10份100w数据的分区,查询确实有速度的提升,但是对于非主键查询来说就惨了,非主键查询基本上要扫描所有10个分区,由于文件的拆分,IO次数增加,查询速度不升反降。因此对于分区的设计要小心小心再谨慎。
如有错误,敬请斧正;欢迎转载,但请务必注明出处;最后,在此向神奇的海螺保证,绝不太监!!!