mysql存储引擎innodb底层存储结构

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

Mysqlinnodb底层存储目录Contents01Part.02Part.04Part.03Part.扇区、磁盘块和数据页B+树存储结构索引组织表数据页结构和行记录扇区、磁盘块和数据页01Part.扇区扇区磁盘数据的最小单元,大小为512字节,在物理层面上是真实存在的;扇区的划分可以让硬盘更好的管理空间。磁盘块由于扇区太小,文件系统按照扇区去读取数据会相当慢,所以有了block(磁盘块)的概念。磁盘块由1个或者连续几个(2^n)相邻的扇区组成,是操作系统与磁盘交互的最小单位,操作系统可以把2^n个扇区数据一次性加载到内存进行快速读取。一个块大小=一个扇区大小*2的n次方,n是可以修改的,由操作系统决定n的大小;数据页数据页=2^n磁盘块,数据页是Mysql操作的最小单位,Innodb里面一般为16KB,lKB=1024字节=2个扇区,不过也可能是8KB、32KB或者其他值,这跟MySQL的存储引擎对数据的存储方式有很大的关系,innodb存储引擎页大小为16KB,16x1024=16384字节。可以存储英文字符16384个,中文8192个。innodb存储引擎页大小为16KB,16x1024=16384字节。可以存储英文字符16384个,中文8192个。拿常见的表举例,一般一行数据占用字节数在100~300个字节。一个数据页在剔除100个字节(存储其它信息)之后,(16384-100)/300=54.28行数据。考虑大多业务场景下(除开日志记录、大字段记录等),y一个数据页正常存储的行数量在16~60之间。表空间、段、区表空间:Innodb存储引擎按照表空间方式对数据进行存放,默认情况下,innodb建立共享的表空间文件,用于存储表所有的有关存储数据,也允许启动innodb_file_per_table为每个表设立自身的表空间,表的数据、索引和缓存BitMap页都放在自身表的表空间文件,但其它信息,如回滚信息、缓冲索引页还是放置在共享表空间。段:多个数据页的集合,innodb的预读比较倾向于对段范围进行预读;区:由连续的页组成,区的大小为1MB,innodb存储引擎会一次预先申请4~5个区;B+树数据结构02Part.B+树B+树是一种树数据结构,通常用于数据库和操作系统的文件系统中。B+树的特点是能够保持数据稳定有序,其插入与修改拥有较稳定的对数时间复杂度。B+树元素自底向上插入,这与二叉树恰好相反。查询数据拥有稳定的对数时间复杂;能更精确的进行范围查询;B+树由B树(自平衡树)演进而来。但由于B树的节点既存储路由(索引),也存储数据,所以相对于B树,B+树更适合范围查询。为什么用B+树而不是B树B+演进同一层级节点按大小顺序排序;节点数满则进行分裂;索引组织表03Part.Innodb索引组织表的数据插入Innodb表本质上是索引组织表(区别于堆表),以索引为驱动指引和操纵数据。换句话说,innodb就是按照B+树的方式去放置数据。对表插入数据,表数据在数据页中按照链表方式进行逻辑顺序排放,数据页空间满则进行依照B+树原则进行数据页分裂,索引键值自下而上成为中间节点或根节点。索引组织表Innodb表本质上是索引组织表(区别于堆表),表数据都按照主键进行顺序存放(逻辑顺序)。在innodb存储引擎表中,每个表都必须要有一个主键,如果没有显式的声明主键,则会按照以下方式进行创建:如果表存在非空唯一索引,如果存在,则使用该列作为主键;如果不存在非空唯一索引,Innodb存储引擎会自动创建一个6字节的指针作为主键,该主键对用户不可见;堆表:区别于索引组织表的顺序插入,堆表的数据在插入时是随机插入,因此从效率上,堆表的插入效率更高,因为省去了插入位置的判断;但索引组织表的查询效率更好,特别是范围查询。Innodb的B+树在实际业务情况下能存储多少的数据量?一个数据页大小为16K,16x1024=16384。索引页中,主要存储了键值和指针,键值以bigint为例,占8个字节,指针占6个字节,则8+6=14,能存储的键值和指针的组合数位16384/14=1170.28571。叶子节点存储着行记录,假如行记录以1k为例,1k已经能满足绝大部分业务场景。那么一页能存储的行数量为16k/1k=16。以一颗三层B+树为例,则可以计算:1171x1171x16=21,939,856。若以一颗四层B+树为例,则可以计算:1171x1171x1171x16=(200亿)。在日常使用过程中,三层的B+树能满足绝大多数的场景。聚集索引和非聚集索引聚集索引聚集索引就是按照表数据的主键构建一颗B+树,叶子节点既存放了表的行记录。因此,表数据也是索引的一部分。一个表通常只有一个聚集索引(既主键索引)。非聚集索引除开聚集索引之外的其它索引,叶子节点除开存放索引列外,还存放着寻找目标行记录的指示信息,mysql需根据指示信息进行二次查找才能找到行记录。包括我们额外创建的普通索引、唯一索引、联合索引。非聚集索引Innodb:标签存储着聚集索引的键值;MyISAM:标签存储着指向行数据的地址,如:(文件号、页号、槽号)。行记录物理地址改变时,索引需要跟着维护Innodb根据非聚集索引列找寻行数据,需在非聚集索引上找到标签,再根据标签找寻聚集索引,通过树查找定位到行数据。例如:右边非聚集索引为3层,聚集索引树也为3层,则需要经过6次IO(抛开预读)才能定位到行数据。在Innodb查询优化器中,会优先考虑聚集索引。数据页和行记录04Part.行记录行记录的逻辑存储顺序行数2行数1行数3行结构包含了下一行的相对位置。在一个数据页里,行记录的存储顺序并非是物理顺序,而是基于链表的逻辑顺序。但由于mysql在查找行数据时,把整个页都加载在内存中,所以即便是链表查找,依然有非常高的效率。另外,针对具体的目标数据,innodb还能使用页目录(槽)缩小查找范围,在相对较小的范围里再使用链表进行定位目标数据。随机读取时则无法使用页目录,只能进行随机性的链表遍历。理想的顺序实际的顺序单数据页单数据页1)新建表2)插入数据行记录内容举例数据从c078开始隐藏列事务id下条记录的偏移量Char剩余字节使用cx20(空格来填充)00000000额外分配6字节主键插入第二行数据非空标识,06转换成二进制为00000110,倒序第2、3位为1,说明第2、3列空值;问题1:变长列表为什么要倒序?顺序排列无法区分当列长度超过255,譬如511,换成16进制为01ff,那么当mysql读取到两个字节时,无法区分是两个列的长度(1字节和255字节)或者是一个列255字节。但是逆序就没问题,假如要表达255,则可以使用ff00,表达511使用ff01,无论如何,遇到ff则默认带上后面字节。(个人猜测,仅供参考)问题2:非空标识只占一个字节,能表示8个列的非空情况,那么第9个列怎么表示?非空标识的8位字节并不是固定的,每超过8位,innodb都会往非空标识的左边增加一个字节,并且表结构会把canbenull字段的个数记录下来,作为辅助作用来区分字节的非空状态。问题3:varchar存储时,只使用了实际存储内容的空间,那为什么不能定的长点呢?Mysql在进行排序或者多维计算时,会在根据表定义申请固定空间来创建内存临时表,varchar过长容易浪费计算内存。所以实际业务建议只申请真正需要的空间。256+255=511行溢出•当varchar数据内容过长时,innodb只会存储varchar内容的前缀部分,剩余数据会存储到溢出页。类型截取长度varchar截取768字节的前缀BLOB截取768字节的前缀text未知,预估跟varchar一样,大多文档中提示text可以当做是大的varchar行溢出会增加查询的IO,在实际业务中,应避免行溢出的设计。行删除在innodb存储引擎中,使用Deletefromtable删除数据并不能真正的回收空间,(MyISAM会释放)只是被删除的行空间能够被复用,但空间并不能被回收。要想回收空间,可以通过:drop/truncatetable;OPTIMEZE释放表空间,但该命令会锁住整表。日常在表主键自增的场景下,建议使用逻辑删除。数据页数据页-双向链表头信息包含了上一页和下一页的偏移量,说明innodb的叶子衔接是双向链表。双向驱动,能更快速的定位数据;满足范围查询的正序和倒序。双向链表数据页查询优化-槽Innodb的槽是一个键值目录,能优化单页里目标记录的查询速度。当innodb要找寻目标行记录,把页从磁盘加载到内存,如果没有其它的辅助信息,那么只能随机的根据链表元素的下一个指向来遍历数据。这里的槽就是用于优化单页中目标数据的查询,innodb根据槽内容使用二分查询,能大大缩小查询的范围。为什么说是大大缩小,因为这里的槽是一个稀疏目录,能让innodb把数据的查询定位到相对较小的范围,而不是定位到具体的行数据,仍需按照下一个指向的原则进行遍历查找。假如,单页里有2000行数据,从1~2000,那么槽目录可能是【1,500,1000,1500】,使用该槽目录,一下子使搜索范围缩小了3倍。当数据变更的时候,需要对该槽进行维护。页分裂数据从页中间分裂的弊端:容易造成空间的浪费,每次分裂都造成了单页有一半的物理空间被浪费,除非主键的生成方式为随机生成,这样空闲的空间还有可能被使用,如果主键的生成方式为自增,空闲的空间会造成浪费。分裂造成单页有一半的数据都迁移到别的数据页,这一半数据均会发生物理地址的改变,加大服务器的运行压力。页分裂PageHeader里面存在三个方便页分裂的属性:•PAGF_LAST_INSERT最后插入记录的位置•PAGE_DERECTION最后插入的方向•PAGE_N_DERECTION一个方向连续插入数据的数量1.若插入是随机的(单方向插入不足5),则直接取中间数据;2.若往一个方向连续插入的数据数量是5,则取定位数据的后面第三个作为分裂点,右边部分移到右新数据页,若向右数据不足三个,则插入数据就是分裂数据;页分裂在实际业务中,建议使用auto_increment,innodb对该属性有“特殊照顾”。从空间利用率和插入效率上比较:auto_increment日期类的自增主键uuid类的主键Thanks.

1 / 35
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功