Mysql+innodb数据存储逻辑。
表空间由段,区,页组成
ibdata1:共享表空间。即所有的数据都存放在这个表空间内。如果用户启用了innodb_file_per_table,则每张表内的数据可以单独放到一个表空间内。(只是数据,索引和插入缓冲Bitmap页面。其他数据还是放到共享表中。)
段
表空间是由各个段组成,有数据段,索引段,回滚段等。数据与索引段都是用B+树数据结构。
区
是由连续页组成的空间,在任何情况下每个区的大小都是1M,每个区由64个连续的大小为16K的页组成。当然64个这个数目也是要以改变的。但区的大小1M是不能变的,当用记启用了参数innodb_file_per_table后创建的表大小默认为96K。前提是先用32个页大小的碎片页后。再申请64个连续页。充分利用碎片页提高存储效率。但会牺牲查找效率。
页
innodb默认每个大小为16K,1.2.X版本后可以设置>innodb_page_size将页大小设置为4K,8K,16K。
常见的页类型有
- 数据页
- undo页
- 系统页
- 事务数据页
- 插入缓冲位图页
- 插入缓冲空闲列表页
- 未压缩的二进制大对象页(blog)
- 压缩的二进制大对照页(blog)
行
页是由n行组成的,这个抽象跟现实生活中的书本的页是一样的。所以数据的记录格式是也是行格式。
mysql有compact和redundant两种格式来存放。mysql 5.1默认compact。行与行之前用链表结构连接起来,redundant主要是用偏移量还确定数据的顺序。
行溢出问题:当行的数据超过16K页的大小,就是溢出。varchar由于数据库不一样,页的大小也不一样的。oracle是varchar2是4000字节,mssql的varchar是8000,mysql的varchar是65532字节。数据库是这样处理的:将溢出的类型数据放到blog页中。问题来了。
数据页的大小16K。即16384字节。为什么varchar可以存储65532字节呢?
mysql是这样处理的:装溢出的数据放到4个未压缩blog中。4*16384=65535。将减去3位指针位就是65532。
总结举一反三
计算机所有的存储结构不外乎:数组,链表,哈希表,树,或是几种组合使用。
如:hashmap是哈希表,1.8后链表那块改成树减少了时间复杂度。内存管理,磁盘管理,编译器的语法树等。
建议非计算机专业的可以看看《数据结构》。很多代码的核心原理在里面都可以找到。