范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

MySQL的B树索引是如何生长的

  分享概要
  本次分享儒猿专栏《从零开始带你成为MySQL实战优化高手》中Mysql索引的内容。本次会先从一个数据页中如何存储和查询数据开始,拓展到多个数据页中查询数据,分析无索引查询时的低效率问题,然后通过页分裂过渡到主键目录以及索引页相关内容,见证一颗索引树是如何一步步生长起来的。
  最后站在更高的角度看下常见的一些索引名词、索引的优缺点以及如何才能设计出更好的索引来,开始分析前我们先来思考下如下的一些面试题:
  1.InnoDB的索引数据结构是什么?为什么用这种数据结构?
  2.聚簇索引和普通索引的区别是什么?
  3.什么是回表操作?它对索引有什么影响吗?
  Mysql索引的B+树的生长流程如下图所示:
  2.B+索引树是如何生长的
  2.1 无索引时的数据查询
  数据页是Mysql中数据管理的最小单元,既然我们要研究索引是如何高效查询数据的,首先我们肯定要搞清楚数据是如何存放的,数据页的结构通过上篇文章我们了解到大概是这样的:
  而数据表中的每行数据就存放在数据区中,数据区中每行数据以单向链表的方式,通过指针连接起来,如下图所示:
  同时每个数据页之间再通过双向链表的方式组织连接起来,如下图所示:
  (1)无索引时的数据查询
  通过以上对数据页以及数据页内部数据结构初步的分析,现在我们就可以看下,如果说要查询某张表的某行数据会经过什么样的流程。
  数据页一开始当然是存放在磁盘中的,一张表对一般会应着多个数据页,查询数据时从磁盘中依次加载数据页到InnoDB的缓冲池中,然后对缓冲池中缓存页的每行数据,通过数据页的单向链表一个一个去遍历查找,如果没有找到,那么就会顺着数据页的双向链表数据结构,依次遍历加载磁盘中的其他数据页到缓冲池中遍历查询。
  大家可以看到,像上面这样的查询方式就有点傻了,因为如果恰好你要查的数据行在这张表最后一个数据页的最后一行,那岂不是所有的数据页都要被扫描一遍,然后每个数据页中也是遍历链表,整体的效果就是以O(n)的时间复杂度在遍历链表了,这样查询的性能肯定是不行的。
  (2)优化数据页内查询效率-槽位
  我们先把目光转移到单个数据页内的数据查询,假如说我们现在已经锁定数据就在某个数据页中了,但是我们该怎样快速的从这个数据页中找到我们想要的那行数据呢?
  通过之前的分析我们可以知道,最傻的一种方式就是遍历数据页中的单向链表查询,一个节点一个节点去扫描,相对应的查询效率是肉眼可见的低。但是如果说可以像翻书一样,根据目录来减小我们查询的范围,相对应的查询效率不就上来了吗,根据这种想法,InnoDB存储引擎设计了槽位这种方式来组织数据页中的多个数据行,槽位信息存放在数据页中的数据页目录中。
  槽位简单来说就是将数据页中的多个数据行分组划分,每个数据行组都找这个组中的主键值最大的那个数据行的地址作为槽位的信息,这样数据页目录中的一个个槽位不就是像是一个个目录了吗,标记好了多个数据行分组的位置信息,如下图所示:
  这下有了数据页目录中的槽位信息,此时要查询数据页中的某行数据不就很简答了,比如我们要查询主键为4的那行数据,直接通过二分法以O(logn)的时间复杂度锁定数据页目录中的槽位2,因为槽位之间都是紧密连接的,可以通过槽位2找到槽位1,从槽位1末尾开始,对分组2中的数据开始遍历,因为每个分组中的数据量都很少,此时在这么小的范围内简单遍历下就可以快速找到主键为4的那行数据,时间复杂度从之前的O(n)降低到O(logn)效率还是挺可观的。
  但是如果你不是通过主键去查询的,槽位此时就排不上用场,你还得一个一个遍历数据页中的单向链表去找到你想要的那行数据。
  2.2 索引的前夕-页分裂
  这里我们先来个小插曲,简单了解下页分裂,这块内容也是后面索引机制能够正常运行的基础。
  我们都知道一个数据页就是16KB大小,当一个数据页中的数据行足够多时就会重新创建一个数据页继续写数据行,如果说我们没有用到索引还好,但是如果我们要在表中创建索引,那么对多个数据页中的数据就有约束了。
  如果新创建的数据页中的数据行的主键值,存在比它上一个数据页的主键值还小的情况,这种情况是不被允许的,如下图所示:
  如果出现上图的情况,多个数据页之间的主键就无序了,而索引机制的实现是要基于多个数据页主键的大小是依次递增的,所以此时就会出现页分裂的情况。
  其实页分裂目的也很明确,就是调整下不同数据页的数据顺序,使得最终按顺序创建的索引页之间,后一个数据页中的每一个数据行的主键值都要大于上一个数据页,当然一个数据页中当然是按照单向链表的方式依次递增的,页分裂流程如下图所示:
  我们可以看到页分裂主要就是调整了下数据页之间数据行的数据的顺序,使得多个数据页之间的主键值是按照顺序来存放的,在这样有序的数据中,高效查询才变得可能。
  频繁的出现页分裂情况,毕竟页分裂要涉及到数据的移动,在性能上也是会有损耗的,这也警示我们减少页分裂的出现概率是非常有必要的,在设计表结构时我们可以尽量使用主键自增长的方式,而不是用很难保证主键顺序的自定义创建主键的方式,使用主键自增长方式,能大大避免说数据页之间主键大小出现顺序错乱的问题,减少页分裂发生的概率。
  2.2 从主键目录到索引页
  查询一行数据,在物理层面就是定位到哪一个数据页中的哪一行数据。在数据页中定位数据的问题,在之前我们已经通过槽位的方式优化了查询的效率,现在我们要解决的是如何在大量的数据页中定位数据页,这就是索引的目标。
  (1)主键目录
  InnoDB存储引擎一开始是使用主键目录的方式,将数据页号和数据页最小的主键值作为一条记录,如下图所示:
  这样的话,我们要查哪一条数据就不用扫描一个数据页内的所有数据再扫描下一个了,直接通过id去主键目录看一下,通过二分查找定位到具体哪个数据页,然后数据页内部通过定位槽位,遍历那个槽位对应数据行分组找到具体的一行数据。
  (2)索引页
  现在有一个问题就是,每张表对应的数据页都有很多,主键目录就会有大量的数据、就有可能放不下,这时InnoDB设计者们就想存放目录数据也是数据啊,为什么不可以使用数据页来放呢,就这样主键目录的信息就被移到数据页来了,而这些数据页就被称为索引页,如下图所示:
  从这里我们可以知道数据页肯定不是简单只存放数据表中的数据的。好了,现在主键目录由于容量有限,我们把主键目录信息移动到了数据页中形成了索引页,但同样的问题不还是会出现吗,一个数据页的大小也才16KB,索引页本身的容量也是有限的,容量不够了该怎么办呢?
  为了解决索引页容量不够的问题,索引页会重新创建和升级,先把超出容量的数据放到一个新的索引页中,然后再加一层索引页,如下图所示:
  由上图我们可以看到,新的一层索引页35它存放的就不是最小主键对应的数据页目录了,而是最小主键对应的索引页目录了,以此类推如果索引页35这里容量也不够呢,那就继续往上一层扩展啊,最终效果看起来就像下面一样:
  大家看出来了吗,由索引页一层一层组成的结构不就是我们经常说的索引树吗,而这棵树在mysql中称之为B+索引树。
  树这种数据结构天然可以使用二分法查询,所以现在如果我们要查询一条数据,从树的根节点开始通过二分法查找,以O(logn)的时间复杂度锁定数据页,然后在数据页中同样使用二分法锁定槽位,在槽位中简单遍历下不就找到数据了吗,相比于没有索引的场景,速度那可是相当快了。
  3.聚簇索引、普通索引和覆盖索引
  关于索引有一些常见的名词我们需要加以区分。
  首先聚簇索引就是像我们上面看到的一棵树一样,它的叶子节点是一个个数据页,这些数据页中存放的都是数据表中每一行的完整数据,所以说如果B+树是以完整数据的数据页为叶子节点的,我们把这个索引树称为聚簇索引;如果一个索引的索引树,叶子节点不是以数据页为叶子节点的,就称为二级索引或普通索引。
  聚簇索引和普通索引最大的区别就是,聚簇索引的叶子节点存放了数据行的完整数据,而二级索引叶子节点只有数据的部分字段。
  而覆盖索引本身并不是一种索引,而是一种查询数据的方式,比如我们对表table中的字段name建立了索引,然后我们执行查询如:select name from table where name like "张%",此时直接从name字段对应的B+树种查询到对应的一批name值,然后直接就返回就行了,也就是说我们想要的字段name它本来就在索引上,我们直接通过二分法高效的从树上直接摘下来就行了,而这种查询方式就称为覆盖索引。
  当然相比于覆盖索引方式,如果查询改为:select * from table where name like "张%",这就不是覆盖索引了,因为此时你不光要从索引树上找到具体的name,还要利用id值回表查询所有的字段。
  4.索引的优缺点分析
  索引的优点当然就是高效查询数据,索引将遍历链表的O(n)的查询时间复杂度优化为了O(logn)的时间复杂度。
  但是索引的缺点也是很明显的,首先在时间角度上,它必须要求主键是要按顺序增长的,无序的主键会带来频繁的页分裂,影响效率;对数据库表的增删改操作的同时也需要维护索引,这部分的维护也是一块性能损耗点;在空间角度上:索引相关的数据和实际数据一样都是要占内存空间的。
  所以索引虽然能够提高查询效率,但是同时也要承担它给我们的系统带来的性能损耗,从这点上来看索引并不是建的越多越好。
  5.三个维度设计好索引
  下面我们从以下三个维度优化下索引的设计
  (1)首先我们从时间角度上
  我们需要为了避免频繁的页分裂,需要尽可能使用主键自增长等方式,保证新增的数据页中的数据行的主键都是递增,避免不必要的页分裂带来的性能损耗和拖慢查询效率。
  另外选择合适的字段作为索引字段也很重要,需要选择基数较大的字段,也就是一个字段可能出现的值比较多,这样我们在B+树中查询时,才能最高效的发挥出二分法查询的威力,如果建立索引的字段基数比较小可能查询时二分查找就会退化成时间复杂度为O(n)的线性查询了。
  (2)空间的角度上
  因为索引数据本身也是要占空间的,可以选择字段长度较小的作为索引字段,这样整棵B+树不至于那么占空间。
  但是如果非得要以长字段作为索引也不是不行,可以采用折中的以字段的前缀作为索引,这样的索引也称为前缀索引,但是这样可能只能用在模糊查询上了,用在group by和order by上就不太适合了。
  (3)作用范围上
  当然我们设计索引的目的,当然是为了更好的用上索引,索引在设计时,尽可能让where、group by、order by这些语句都能用上索引。
  6.面试题剖析
  1.InnoDB的索引数据结构是什么?为什么用这种数据结构?
  2.聚簇索引、普通索引区别是什么?
  3.什么是回表操作?它对索引有什么影响吗?
  END

谷爱凌妈妈说的一段话,值得我们学习你长大不需要感谢我,你一点都不欠我的,我只希望你自由丰富快乐勇于尝试挑战自我享受自我。谷爱凌正是在这样的教育熏陶下,才造就了她勇敢自信有力量的性格,让她在冬奥会自由滑雪女子大跳台的精炼无双的男孩名字,起凤腾蛟,典则俊雅好的名字用字凝练,搭配独特,让人过目不忘。姓氏与名字的搭配相得益彰,既能突出姓氏的特点,又与名字结合的天衣无缝,读起来平仄畅快,一气呵成。今天子墨老师给大家推荐如下精炼无双的男孩名求给孩子做过腺样体等离子消融术的亲们分享一下经验,感谢?我家小孩刚做完,切了扁桃体和腺样体,之前也是一直犹豫要不要做这个手术,看到有些说做手术不好吃药就可以了,在咨询过医生后还是决定手术,一个是要小孩少吃点苦(晚上睡觉缺氧导致睡不踏实,生完孩子后,在某些时候会觉得后悔吗?从生完孩子到成长的某时某刻,都有后悔的感觉。怀孕时最舒服,可以躺平,不用上班,即使妊娠呕吐三个月,也没觉得是苦。顶多是委屈。后来娃生出来,熬夜喂奶,家人的不理解,生活习惯不同,甚至你理解的人世间最大的悲哀是什么?数十年来,公知们绞尽脑汁丶不遗余力地诋毁毛泽东思想,抹黑社会主义祖国,结果徒劳无益,空留笑柄,大山依旧在,朝阳依然红,这对于那些屑小们,不能不说是一种悲哀。在中国有百分之九十以上的14岁女儿坚信自己得了抑郁症,作为母亲该怎么引导?做为母亲在这个时候应该领女儿去看心里医生,如果真得病了,就进行治疗,开导女儿,鼓励她能够战胜抑郁症,不要给她压力,劝导女儿参加娱乐项目,希望您的女儿早日从抑郁的阴影里走出来!孩子受有机奶粉与普通奶粉的区别如今,市面上的有机食品是越来越多,包括有机蔬菜有机水果有机水稻,就连奶粉如今也打着有机称号。为何一提到有机两字,就特别引起关注。为何只要打上有机两字的食品,价格就会高出许多呢?就拿新生婴儿在月子里的正常作息在娃出生之前,杂七杂八看过一些有关新生婴儿的书和文章,当时想着每个案例里面的娃都这么乖的,我也好想自己肚子里的娃也这么乖。所以我自己在孕期的作息是很正常的,就是按照自己平时的作息,独自带娃随笔最近,可宝能体谅妈妈了,天气暖和了,昨天领她去海边,她坐在婴儿车里可能手有点凉,她以为我手也凉,说妈妈,我的帽子里可热乎了,要不你把你手伸进来捂捂啊(暖和暖和),当时听了特别感动。孩子在家走路,楼下说扰民怎么办?我家男孩4岁,正是活泼的时候,但他真不是那种疯起来没完的男孩子。只是可能不会像大人那样走路。从客厅到卧室会跑过去。并没有在屋里乱跑,楼下说声音很大,找过我一回,我说争取10点半让他冲孩子吼叫实际上并不能改变他们的行为(一)在日常生活中你为什么总忍不住对孩子大吼大叫?要解决这个问题需要了解自己理解日常促发吼叫的因素及我吼叫的深层原因以便让自己的教养方式适应孩子的天性。1。了解自己先诚实面对自己有了孩子
12句让女生荷尔蒙爆发的晚安情话,值得收藏和直男直女谈个话都能把人气死,更别说谈恋爱了!学会这些情话,你也是最闪亮的那颗星。12句让女生荷尔蒙爆发的晚安情话,句句露骨,撩到她受不了1你最可爱。我说时来不及思索,而思索之后,长期不换微信头像的人,往往是以下这4种人,遇到请好好珍惜现在的社交软件发达,然而微信是最普遍的一种社交方式。别小看它只是一个沟通工具,实际上,它是你行走中的个人名片,它所展示的一切都是带着你的整体形象。别人通过添加你的联系方式,第一眼看提醒男人出轨的女人,从这四个方面会露出端倪对女人来说,出轨多数是因为爱情,也就是说,一旦女人出轨,对婚姻的伤害就会非常的直接。毕竟出轨最怕的就是走心,如果只是玩玩逢场作戏,虽然同样给婚姻带来伤害,但是伤痕至少会浅一些。我们为什么离婚后,女人一般都会比男人过得更艰难?为什么离异后,女人一般都会比男人过得更艰难?我认为,除了我们的传统观念和社会环境,对女人有着更多的要求之外,最根本的原因还在于男人与女人的思维方式性格和情感心理不同(但这并不能代表女人最有味道的两个宝贝,男人都喜欢品尝第二个红楼梦里面贾宝玉说过这样的话女儿是水做的骨肉,男人是泥作的骨肉。我见了女儿,我便清爽见了男子,便觉浊臭逼人。可想而知,女人的魅力有多大,而这种魅力,不仅仅体现在外貌上,更体现在内在研究最舒服的4种方式,做完感情会越来越好第一相互尊重,地位平等,学会倾听,适当安慰。不管是男人还是女人,每个人或多或少都会有自己的烦恼。有时候,我们不想告诉父母,怕他们担心,但我们可以告诉我们爱的人。如何处理好男女之间的中年女人对你芳心暗许了,根本不会拒绝你这5个要求在感情面前,很多时候有的人不善于去表达自己内心的真实情感,而是用一些方式举动来暗示。对于女人来说,也许面对爱情没有那么直接,但是她会通过自己的行为来表明对你的心意。所以说,当女人不黄河我到了,南墙也撞了,故事我懂了,也忘了到了黄河,才知道忍让的人已经无路可退,撞了南墙,才体会到感情被欺骗的心痛,喝了烈酒,才明白卑微的人设换不来真爱。我懂了,你不是那个能和我荣辱与共的人,我们的故事就到这里吧,你,不是女人有意给你泄洪,说明她真的对你动了心爱情有时候,真的与考试很像,男生有时猜错了女生的心思,估计就会与美好的爱情失之交臂。所以,奉劝很多直男们,千万不要以为你毫无浪漫的爱会是女生最想要的依靠,有些时候,恋爱前,不做些攻偷偷摸摸喜欢你的女人,会有这4个表现,别不懂女人在开始一段感情之前,基本上都会表现的很矜持,但是如果一个女人偷偷摸摸喜欢你了,就算不会主动去追你,那么她一般也会有一些特别的表现,那么一起来看看一个偷偷摸摸喜欢你的女人,一般都女人假爱你的3种表现,特别是第3种,都是骗你的爱情里的真真假假,假假真真,犹如雾里看花,很难辨别,有些时候,我们以为眼前所遇到的人,就是自己这辈子想要追寻的那个人,你以为你遇到了对的人,殊不知你爱的人,她根本就不爱你,只是喜欢