mysql深度剖析一(底层数据结构)

衍变

二叉树
二叉查找树(容易形成链表)
二叉平衡树(可以自动调整高度,但层数容易过高)
多路平衡查找树即B树(层数控制了,但每个节点存有数据,导致每个磁盘页存不了多少索引,导致层数升高)
传统加强版多路平衡查找树即B+树(每个磁盘页可以存更多索引,进一步控制了层数,但最底层是单向链表)
innodb的B+树(叶子节点是双向链表,提升了范围查找与排序效率)

索引是啥

一种为了使查找方便而 排好序 的数据结构

查找需要几次磁盘io呢

查找索引为30的数据
mysql深度剖析一(底层数据结构)_第1张图片

1)先将B+数的根节点加载进内存中,发生了一次io;
2)30大于15,小于56,找到了30所在的磁盘页地址,再次加载进内存,发生了第二次io;
3)30大于20小于49,进一步找到了30所在磁盘页地址,再次加载进内存,发生了第三次io;
4)最后找到了索引为30所在地址及其数据;
通常根节点会常驻内存

B+树与页的关系

mysql深度剖析一(底层数据结构)_第2张图片

一页的大小是16384个字节,即16kb,可以通过执行show global status like ‘Innodb_page_size’来查看,此值可以改,但不推荐。为啥是16kb呢,试想若一页设定为非常大,即一页存放所有数据,只经过一次io就将数据加载进内存,对内存压力很大,而且一次io加载几百兆,甚至更多,也弄不了那么多,时间也长。

每一页存的是啥,可以存多少呢

每一页存的是索引值和指向下一层磁盘页的指针,称为一对,按照上边图,这里假设一对大小为8字节+6字节,14字节,那么16384除以14等于1170,即第一层可以存放1170对。第二层就有1170乘以1170对,第三层叶子节点根据不同的存储引擎可以存data,也可能存指针,所以按照一张表几十个字段,按照最大1Kb作为叶子节点大小,那么一页可以存16个数据,所以第三层可以存放1170乘以1170乘以16约为两千多万个数据;
一张表如果有上亿数据,一般会分库分表

为啥选择B+树而不是B树

mysql深度剖析一(底层数据结构)_第3张图片

每个节点带有数据,按照1Kb算,则一页可以存16个数据,那么要存2000万数据,需要多少层呢,以16为底,取2000万的对数,约为6,即16的6次方约为1600万;6层其实也不多,但也要6次磁盘io,时间已经翻倍了;

Myisam与innodb底层数据结构的区别

相同点:都是基于B+树,节点中的数据索引从左至右递增排列
三个不同点:非叶子节点有无数据,主键索引与非主键索引存储结构不同
Myisam中,.MYI文件存的是B+树,先在该树上找,而myisam叶子节点存放的是索引所在行的磁盘文件地址,再根据地址去.MYD文件中找到对应数据;索引与数据分开放,所以myisam的主键索引为非聚集索引;另外非主键索引也是这样存储;
Innodb中,.ibd文件存放的就是B+树,并且叶子节点是索引+所在行的数据,所以innodb的主键索引为聚集索引;非主键索引的叶子节点存储的是主键值;

非主键索引,二级索引,辅助索引是一个概念

非主键索引也是非聚集索引,需要回表,innodb存储引擎有且只有一个聚集索引
非主键索引的叶子节点存放的是该索引以及主键值,通常需要再次回到主键索引的B+树中,查找完整数据,此为回表。
二级索引比主键索引占用内存少,因为主键索引的叶子节点存放有完整数据,导致磁盘io每次传输数据更多;所以mysql系统会判断当select所查找的字段在二级索引和主键索引的叶子节点中均存在时,会优先选择二级索引去找即全索引扫描。若select所查找的字段在二级索引中只有一部分,则优先选择主键索引,这样可以避免回表,因为回表成本更高,而扫描主键索引的叶子节点,拿到所需数据,此即为全表扫描;但是若采用二级索引,则先拿到叶子节点中的主键,再根据主键去主键b+树中找到所需数据,相当于回表了,成本比全表扫描更高;
对于select * where xxx…,若xxx是非主键索引,线程此时无法扫描非主键索引的所有叶子节点而拿到数据,即无法走覆盖索引,也即无法走全索引扫描,此时mysql内部会进行比较,一是此时扫描主键索引树的所有叶子节点(全表扫描)拿到所有数据需要多长时间,二是此时根据二级索引叶子节点中的主键去主键索引树中回表查询需要多长时间,两个时间谁短就用谁;

覆盖索引

覆盖索引一般针对的是辅助索引,整个查询结果只通过辅助索引就能拿到结果,不需要通过辅助索引树找到主键,再通过主键去主键索引树里获取其它字段值;
即二级索引的叶子节点中的数据字段就覆盖了需要select的字段,不用回表就可以拿到。
二级索引树的叶子节点中只有二级索引字段和主键id,所以当select其他字段时,会回表;

为啥推荐innodb表必须建主键

不建也行,系统会找表中唯一键构建索引,如果无唯一键,则会用6字节的隐藏字段rowid,用它作为聚集索引来组织存放数据;所以自己先建好主键,系统会直接用主键构建B+树索引,岂不快哉

为啥推荐使用整型自增主键

使用自增主键,mysql底层在构建B+树过程中不断调整的次数要少,可以做个试验,针对两组数据,一组无序,一组有序,分别执行insert,构建B+树,构建网站是https://www.cs.usfca.edu/~galles/visualization/Algorithms.html
数据顺序如下:
1 9 3 7 5 2 8 4 6
1 2 3 4 5 6 7 8 9
结果无序的一组,调整了四次,自增有序的一组调整了三次,当数据量大的时候,调整次数差别就明显了,所以调整次数越少,构建B+树效率越高。
使用整型易于比较,字母的话要转成ASCII码

联合索引也即复合索引

一张表不推荐建太多的单值索引,用几个字段组成的联合索引覆盖80%的sql语句;最左前缀原则的实现原理是先按从左到右的字段依次排好序,构建一个B+树,在这个基础上查找才有意义,比如(a,b,c)三个字段构建联合索引,如果只以b为条件,那么无法查,因为只有在a字段排好序的基础上,b字段才有序;

你可能感兴趣的:(mysql,mysql)