mysql,对it打工人,这个几乎是必备的技能之一。mysql可以解决我们平时工作中的大量的、有关增删查改的问题。所以想深入了解mysql,我觉得关键在于他的增删查改背后的算法,开搞。
面对增删查改等问题,直接通过场景来看吧
场景1
有很多个数据,如上图右边的两个链表,顺序查找会会遍历每一个元素,会很慢,尤其是数据量很大的时候,遍历整个表都会会一次都会消耗大量的时间,而右边是一个二叉树,很明显可以看到,二叉树找到我们要的元素,最多只需要比对3次。
常见的各种树的算法复杂度
操作 | 二叉查找树 | 平衡二叉树 | 红黑树 |
查找 | O(n) | O(logn) | Olog(n) |
插入 | O(n) | O(logn) | Olog(n) |
删除 | O(n) | O(logn) | Olog(n) |
结论:链表不得行哦~
直接上二叉树吧
于是乎制作成二叉树,如下图右边的树。左边的链表89号元素需要遍历查找,而89的元素在在二叉树中,一次比对后就完成了定位。所以单一个二叉树就大大的优化了效率。
mysql有使用二叉树吗
没有!为什么呢?
想想一下这个一个场景:有一堆连续的数组,放到二叉树里边,那么他的二叉树结构就是一个链表的样子!说明了说在个别场景中,二叉树相对链表并没有优势可言。
ps:安利一个网站:https://www.cs.usfca.edu/~gal...
结论就是:二叉树也不见得很好,个别场景下它就是个链表
红黑树(二叉平衡树)
于是乎来到了红黑树,如下图。
- 性质1:每个节点要么是黑色,要么是红色。
- 性质2:根节点是黑色。
- 性质3:每个叶子节点(NIL)是黑色。
- 性质4:每个红色结点的两个子结点一定都是黑色。
- 性质5:任意一结点到每个叶子结点的路径都包含数量相同的黑结点。
红黑树的应用比较广泛,主要是用它来存储有序的数据,它的时间复杂度是O(lgn),效率非常之高。
TODO:
补充红黑树的伪算法
这样看起来,红黑树效率会高一些,但是为什么mysql用的不是红黑树呢
因为实际场景的时候,数据量会很大,比如几百万的时候,树的层级可能达到20层,其实这个速度是很快了,但是依然不够高。在数据量大的时候,查找速度慢,它很难避免。
到这里可以得出,数据查询的效率,跟数据层级是有关系的
所以这里是不是可以思考一下:我们就让这个红黑树高度可控,控制在一个指定的深度,比如就三层,就会快很多?
这样子做得话,我们只能在一个节点上,挂载更多的节点,而不是只是两个。
实际上这就是b树
看上去b树效果已经很好了,mysql有用到吗? NO!
实际上mysql用的是b+树
b树和b+树在底层存储数据的区别,叶子节点有一个指针指向左右,这样可以按照顺序地在叶子节点上遍历数据。
在mysql中b+树的特点
mysql的b+树的第一层节点的大小是16kb。可以通过sql语句查询到:show global status liek "innodb_page_size"
。其实第一层大索引大致可以存放(8+6)的数量是1170个的样子,第二层的节点也是1170个样样子。第三场就单纯存放索引,大概存放16个。
所以mysqlb+树的索引,大概可以存放的数据量在2000万个左右。
其实实际情况中,根节点的数据是常驻内存的,并不是每次查询都会重新载入一遍到内存。所以千万级别的表,查找依然很快。
实际上b+树的层级是可以大于3层的,需要的话可以设置。单实际上到这一步的时候,早就应该分库分表的。也就是为什么mysql不建议存储数据量大于2000万行左右数据的一个原因。
MyISAM和innodb的区别
tips:
myisam引擎mysql数据文件夹里边的文件简介:frm存放的是表结构,MYD是存放的数据,MYI存放的树索引。
那么myisam的数据内容,就是:
当查找col1(假如col1是索引)等于30是,就是去myi的的文件里边找,按照左边的这个树形结构,定位到数据地址,拉出里边的索引位置。通过索引记录的位置,迅速定位到数据表的行的地址。这就是MYIsam
但实际中我们用的更多是innodb的引擎
为什么要用innodb呢?
innodb的文件结构。
innodb在mysql数据库文件夹下的数据文件格式是:
frm代表表结构文件, idb存放的既包含数据,又包含索引。这几个名称猴嘴的mysql文件,相信做过数据迁移的童鞋,都不会觉得陌生,甚至看到他会有一丝丝气愤,当初就是这些让自己经常加班!
所以可以看出,innodb叶子节点上存放的不是索引,而直接是数据。Innodb的数据是直接挂在索引下的!
那么这些差异,导致不同引擎的数据库,都有哪些差异呢?
好几种索引介绍
聚集索引(聚蔟索引):innodb叶子节点包含了完整数据的索引。
非聚集索引(离散索引):myslam 叶子节点上,没有存放完整的数据。
为什么innodb表建议必须建主键,并且推荐使用整形的自增主键呢
uuid不合适,开篇死。因为uuid不是递增的
因为innodb的数据,必须有一个b+树的索引结构,来组织他的数据。mysql如果不建立主键,他就会进入这张表的第一列,判断如果这列数据每一个数据都是唯一的,那么就用这一列当做索引。如果遍历完了每一列,都没有唯一的列,那么mysql就会悄悄地为你建立一列隐藏列。这样一下走下来,就花费了太多运算了,所以推荐用户自建自增索引。
为什么建议自增整形呢?(雪花算法也是自增的。)因为查找的时候需要经常比对大小,每一层会逐个比对大小,用asii码去比对。而整形,在这一块比对的时候会快一些,所以要求整形。为甚自增呢?
为了快。
比如遇到范围查询的时候,定位到了一个元素,是不是就很快能判断上下位置的元素。
建立索引的时候可以选择btree,还有hash。hash是什么样的呢
hash定位速度很快哦。超级快!
首先算hash值,然后根据hash存放在某个位置,这个数据里边存放了值和节点的地址。当有多个的时候,就在这个后边直接添加。当数据量不大的时候,hash的效率非常高。
但实际上工作用绝大多数的时候都用的是b+而不是hash(99.99%都不是)。为什么呢?
- hash冲突,只是一个
- 最主要的是:不支持范围查询。当有返回查询的时候,就只能遍历查询。
所以范围查询hash挂掉了,那么b+树就能hold住吗?
b+树的叶子节点有一个双向指针,来保持数据的连贯性。此外b+数据帮我们维护了一个从做到右的一种递增结构。所以范围查询,只要定位到了上限或者下限,直接顺藤摸瓜,很快就能完成定位。这也是为什么b+树叶子节点要维护一个双向指针的原因。
即使你没有按照顺序存放数据,b+树,也会帮你整理好顺序。比如7,8,6,也会将6放到78前。所以如果不是递增,调整顺序会消耗计算,尤其是在节点分裂的时候,要影响整个树的结构的时候,结构变化就会占用很多资源。但是如果顺序存放,反正结构性调整的概率是比较低的,相当于也是加快了存储的顺序。
这也是添加了索引为什么会让存储变慢的底层原因。
常见的联合索引的底层存储结构长什么样子的
从上图,可以看一下二级索引的特点,二级索引紧贴在一级索引后边,question:为什么二级索引长成这样,实际使用时运作机制是什么样的。
其实:索引是一种排好序的数据结构
想要理解多级索引的特点,其实,理解好mysql处理索引时,是如何为多级索引排序的就好了。
其实查找时,方法就是逐个比对。如果第一层,就已经可以比对处顺序了,那么这些数据,就直接就按这个顺序来排就行。如果第一个索引大小相同,那就根据第二个来排序,如果第二个相同,就看第三个。如果第三个也相同,就看主键,如果没有主键,那就看隐藏主键(所以建立自增索引很重要!)。