mysql调优思路与mysql底层理解

65 阅读9分钟

mysql调优

为什么mysql不用二叉树?
因为二叉树的话如果索引是连续自增的话效果不大。

image.png

一般一条16k 一行可以放16k/14b=11700 如果data一行放1kb的话。总的就是11700平方 * 16=2千多万
mysql高版本就把非叶子节点提前放到内存里面的。
B树和b+树的区别
b树就是每个节点可以存储上千个节点,还有就是每个节点存储对应的数据。

image.png

b树
b+树在b树的基础上有更多的优化,
首先在非叶子节点没有数据,然后数据全部存放在叶子节点里面。而且叶子节点有一个双向链表,且首尾相连,查找的时候非常快。

image.png

mylsam查找过程:
先去b+树去找到该数据索引的内存地址,然后去.myd文件里面根据地址值去查找数据。这就是非聚集索引。

image.png

什么是聚集索引:
叶子节点包含了完整的数据记录的索引

image.png

非主键索引和非主键索引区别:
先找到非主键索引所存放的主键索引值,再根据这个索引去主键索引去找对应的值。因为存在回表,所以有点慢。
主键索引:
主键索引b+树叶子节点就是直接存放的值,直接查找。
而非主键索引的话就是叶子节点存放的是主键的值,再根据主键的值去主键索引里面去查询。这里就涉及到回表的操作,所以会慢很多。

image.png

为什么用自增会比uuid好?
如果没有主键索引,也没有别的索引,mysql后台会建一个rowid索引。推荐建立主键。
1.uuid索引查找的时候比大小会比自增大
2.uuid占用空间比自增大。
3.在插入的时候自增id永远都会放到最后面去,而uuid插入可能会放到中间,然后链表可能会分裂,也可以用雪花算法,因为雪花算法趋势是递增的,只有少量不是递增

为什么不用hash结构来存储?
因为hash虽然查找快,但是会有hash冲突问题,最主要的还是hash仅仅只能满足= 和in的查找,比如范围查找就不好找了。

联合索引:
最左匹配原则
(name,age,sex)只有查找的时候是(name ,age,sex)(name,age)(name)才会有效。
联合索引也会有一个回表的过程
不满足最左匹配为什么会失效:
因为查找的时候联合索引已经生成了,联合索引的树是按照name,age,sex的优先级来排列的。如果查找age,sex就会不按照name最优先的查找。就会相当于是全表是扫描了。假如是name,sex的话就只会走name一个字段

image.png

联合索引查询name>?的时候不是很适合,
因为会首先在联合索引表里面查询找到大于name值得数据的主键id,然后才会去主键索引表里面去找对应的name>的数据,相当于会回表。执行器就会直接全表扫描,直接不会表会更快。

image.png

索引覆盖
当查询的时候查询的内容中没有联合索引里面的值的时候就会去回表,a是主键,bcd是联合索引的话,查询的时候就查bcda的字段,这个值在联合索引里面就有,所以就会走索引。如果查询*就会先在联合索引表里面查询一次,再带着主键去主键表查询一次所有的数据。这就是索引覆盖。就是直接走索引,不去回表就叫覆盖索引

索引下推:当使用二级索引查询,需要回表的时候是默认一一条回表的,但是我们可以设置让他变成几条
执行优化器:
假如查询b>1的所有数据的话,是要回表的,而b>1在联合索引里面相当于全表扫面了,因为b所有的值都是大于1的。这个时候执行优化器就会判断是全表扫描快还是用索引快然后就会根据情况来使用索引。还有就是假如查询的b<2,在联合索引中只有一个小于二的话就只有一个数据,然而不走索引,走全表扫面会慢。所以这个时候就会走索引。

走了索引,默认查询出来就是按照索引排列的。

索引扫描:当select b from table时怎么走?
答案是会走索引,因为虽然都是所有表都会走,但是呢在联合索引这边存放的数据不是完整数据,在主键索引那边是完整数据,所以每一页的数据相对而言联合索引的行数可能会多一点点,但是不是完整的,所以页数就会少一点。页数少查询的时候就会快一点。所以会走索引

image.png

groupby应该注意什么?
当创建了联合索引bcd的话,如果我们要查询select * from table group by b c d的时候就会有两种走法,一种是直接全表扫面之后,再排序。还有一种是直接查询联合索引,然后再去回表。这两种办法执行器当然是选择全表扫瞄再排序,这样比后者速度快。还有就是如果查询的是b不是就不回表了,当然是走索引会快。所以groupby的时候查询最好不要用,这样会导致不走索引走全表扫描。

数据大的时候多个页合起来就形成了索引页

image.png

这就是b+树的叶子节点索引页为上面的页,数据为下面的数据页。
mysq的page:
是属于innodb的页,每一页大小为16kb,作用就是可以加快查询效率。
是怎么加快查询效率的呢。如果没有页的话,如果查询某一个数据就会去磁盘里面一个一个比对,会很消耗io次数,效率低下,有页的话,就会直接一页一页的加载到磁盘里面去,减少io次数,所以效率高。那么页是怎么快速找到所需要的数据呢?是因为在页里面的数据都会有一个排序是从小到大升序排列的。查找起来很快。还有就是每多少页就会固定生成一个目录,就是所对应页的第一页作为目录。然后就会先去找目录,再找页数,达到快速查找的目的。

image.png

varchar索引失效问题;
a是int,e是varchar。

image.png

为什么最后的是e=0没有走索引?
因为e是字符类型,我们默认的是字符转数字,而不是数字转字符。所以123都是会走索引,但是最后一个数字1不能走索引是因为我们默认的是字符转数字。而e作为一个字段显然是不好转的,索引就不会走索引了,就会进行全表扫描,这就是导致索引失效的原因。还有就是一些加减乘除操作运算的时候也会导致索引失效。

mysql为什么不使用调表的数据结构?
什么是跳表?

image.png

把所有的数据有序放在最下面一层。然后用链表把他们链接起来。然后上面层就是索引
如何实现查找?最上面的索引如何建立?就是基于最下面的链表加一个类似于目录的索引,左闭右开。
当查找数据时,先从最上面开始查找,然后的话就进行比他大的向右,比他小的向左原则向下查找。
在插入删除时:
插入时会根据索引找到要插入的位置,然后先插入最下面的数据,然后再更新索引层。
删除的时候也是一样的,先插入最下面的数据,再更新索引层。
在数据量很大的时候调表数据结构的索引可能会很高层,当要查找的时候会消耗大量的磁盘io.

调表和b+树对比:
和b+树相比的话就是b+树最多3次io就完了,所以在磁盘查找中b+树的查询效率就显得很快了。然而在redis中的zset数据结构就是基于跳表实现的,因为redis是基于内存的,所以磁盘io的优先级就没有那么高了,所以使用了跳表的数据结构。

然而跳表的数据写入会比b+树快速,但是呢在数据库的实现过程中,我们会有28原则,原则就是说2分的写入8分的读取,所以呢,使用b+树更佳。

b+树的插入:
假如是增id的话
叶子节点没有满的情况。就会直接把数据放到最后一个叶子节点里面去。

image.png

叶子节点满了,非叶子节点也满了的话就会分裂出一个叶子节点出来,然后就会把前一个叶子节点的最后的一个数据,作为后一个叶子节点的第一个数据,然后新插入的数据放在新的叶子节点后面。与此同时,更新非叶子节点。

image.png

为什么不把新更新的键作为第一个呢?
因为如果说把6放在原来的地方,是否要判断7是新增一个页,还是说就加在以前已经存在的地方。如果要插入到已经存在的页的话就要

image.png

第一:如果将数据8放在数据页2中,当数据页足够多时,是否要判断将数据页10放在另一个已存在的数据页中,而不是新增数据页,以此类推,直到最后一个数据页,这样无疑会非常的繁琐,相当于遍历剩余所有数据页和数据。这肯定是不可取的。
第二:将数据页2空出来了,下次如果有新的数据插入,假设这个数据介于7和8之间,那么它就可以直接插入,不必在新增数据页。