| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 大数据 -> 深入理解MySQL索引知识 -> 正文阅读 |
|
[大数据]深入理解MySQL索引知识 |
一文彻底搞懂索引前言索引在MySQL中也叫做键(key)是存储引擎用于快速找到记录的一种数据结构。索引对于良好的性能十分关键。尤其是当表中的数据量越来越大时,索引对性能的影响愈发重要。在数据量小且负载较低时,不恰当的索引对性能的影响可能还不明显,但是当数据量逐渐增大时,查询性能则会急剧下降。索引优化应该是对查询性能优化最有效的手段。索引能够轻而易举地将查询性能提高几个数量级。索引是在存储引擎层实现的,而mysql有多个存储引擎索引的结构有多种innodb和myisam使用B树B+树memory存储引擎采hash索引。 一、索引的基础1.1 索引简介(本质是一种数据结构)1.1.1 使用索引能够快速查找出某个或者是多个列中有特定值的行,如果没有索引例如表有2万条记录,执行select name from student where id = 9000;mysql就必须整表扫描直到找到id = 9000的这条记录。如果在id列上创建索引mysql就不需要整表扫描,直接在索引里找9000这个值就可以对应数据库表的记录。提高查询效率。也可以将索引简单的类比字典目录,当我们去查找某个汉字时可以使用字母或者偏旁部首去查找达到查询到这个汉字的汉字的页码的目的。 1.2 索引优缺点优点(排好序的快速查找数据结构): 缺点: 1.3 索引的设计原则?索引设计不合理或者缺少索引在数据量少的时候,它的性能影响不大。但是当数据量达到几百万上千万时,高效的索引能提供良好的查询性能,反之索引设计不合理或者缺少索引的情况查询性能就非常差。索引我们得考虑索引的设计原则: 1.4 索引的分类?1.单列索引:即一个索引只包含单个列,一个表可以有多个单列索引 1.5 创建索引的几种方式?1.CREATE INDEX indexName ON tableName (columnName(length)); 2.ALTER TABLE tableName ADD INDEX indexName(columnName); 3.建表的时候创建索引: 1.6 什么是B树?B-树就是B树,多路搜索树,树高一层意味着多一次的磁盘I/O,下图是3阶B树 1.7 什么是B+树?
哈希索引就是采用一定的哈希算法,把键值换算成新的哈希值,检索时不需要类似B+树那样从根节点到叶子节点逐级查找,只需一次哈希算法即可立刻定位到相应的位置,速度非常快。 1.7 什么是哈希索引?哈希索引就是采用一定的哈希算法,把键值换算成新的哈希值,检索时不需要类似B+树那样从根节点到叶子节点逐级查找,只需一次哈希算法即可立刻定位到相应的位置,速度非常快。 1.8 为什么要使用B+树?B树和B+树的区别是什么?虽然我们可以通过查看mysql索引结构是B树,但是实际中mysql使用的是B+树是B树的变种。b树和b+树的区别: 1.9 Mysql的索引结构为什么要使用BTREE和B+TREE?二叉排序树: 虽然能做到节点数据的排序功能,数据量小的时候确实是个不错的选择。但是我们知道一般来说对表中的每个列进行添加索引那么这个列的数据量是非常大的使用二叉排序树在大数据量的是时候,它的高度是不可控的也就是说如1000w条数据会导致二叉树的高度非常高,查找效率低io操作频繁。而且不保证平衡最坏的情况下会退化成链表。 二、索引的进阶2.1 InnoDB 的索引模型在InnoDB中,表都是根据主键顺序以索引的形式存放的,这种存储方式的表称为索引组织表。又因为前面我们提到的,InnoDB使用了B+树索引模型,所以数据都是存储在B+树中的。每一个索引在InnoDB里面对应一棵B+树。假设,我们有一个主键列为ID的表,表中有字段k,并且在k上有索引。这个表的建表语句是:
表中R1~R5的(ID,k)值分别为(100,1)、(200,2)、(300,3)、(500,5)和(600,6),两棵树的示例示意图如下。 2.2 索引维护B+树为了维护索引有序性,在插入新值的时候需要做必要的维护。以上面这个图为例,如果插入新的行ID值为700,则只需要在R5的记录后面插入一个新记录。如果新插入的ID值为400,就相对麻烦了,需要逻辑上挪动后面的数据,空出位置。 而更糟的情况是,如果R5所在的数据页已经满了,根据B+树的算法,这时候需要申请一个新的数据页,然后挪动部分数据过去。这个过程称为页分裂。在这种情况下,性能自然会受影响。 除了性能外,页分裂操作还影响数据页的利用率。原本放在一个页的数据,现在分到两个页中,整体空间利用率降低大约50%。 当然有分裂就有合并。当相邻两个页由于删除了数据,利用率很低之后,会将数据页做合并。合并的过程,可以认为是分裂过程的逆过程。 基于上面的索引维护过程说明,我们来讨论一个案例: 插入新记录的时候可以不指定ID的值,系统会获取当前ID最大值加1作为下一条记录的ID值。 也就是说,自增主键的插入数据模式,正符合了我们前面提到的递增插入的场景。每次插入一条新记录,都是追加操作,都不涉及到挪动其他记录,也不会触发叶子节点的分裂。 而有业务逻辑的字段做主键,则往往不容易保证有序插入,这样写数据成本相对较高。 除了考虑性能外,我们还可以从存储空间的角度来看。假设你的表中确实有一个唯一字段,比如字符串类型的身份证号,那应该用身份证号做主键,还是用自增字段做主键呢? 由于每个非主键索引的叶子节点上都是主键的值。如果用身份证号做主键,那么每个二级索引的叶子节点占用约20个字节,而如果用整型做主键,则只要4个字节,如果是长整型(bigint)则是8个字节。 所以,从性能和存储空间方面考量,自增主键往往是更合理的选择。 有没有什么场景适合用业务字段直接做主键的呢?还是有的。比如,有些业务的场景需求是这样的: 2.3 覆盖索引在下面这个表T中,如果我执行 select * from T where k between 3 and 5,需要执行几次树的搜索操作,会扫描多少行?
1.在k索引树上找到k=3的记录,取得 ID = 300; 2.再到ID索引树查到ID=300对应的R3; 3.在k索引树取下一个值k=5,取得ID=500; 4.再回到ID索引树查到ID=500对应的R4; 5.在k索引树取下一个值k=6,不满足条件,循环结束。 在这个过程中,回到主键索引树搜索的过程,我们称为回表。可以看到,这个查询过程读了k索引树的3条记录(步骤1、3和5),回表了两次(步骤2和4)。 在这个例子中,由于查询结果所需要的数据只在主键索引上有,所以不得不回表。那么,有没有可能经过索引优化,避免回表过程呢? 覆盖索引 基于上面覆盖索引的说明,我们来讨论一个问题:在一个市民信息表上,是否有必要将身份证号和名字建立联合索引?
我们知道,身份证号是市民的唯一标识。也就是说,如果有根据身份证号查询市民信息的需求,我们只要在身份证号字段上建立索引就够了。而再建立一个(身份证号、姓名)的联合索引,是不是浪费空间? 如果现在有一个高频请求,要根据市民的身份证号查询他的姓名,这个联合索引就有意义了。它可以在这个高频请求上用到覆盖索引,不再需要回表查整行记录,减少语句的执行时间。 当然,索引字段的维护总是有代价的。因此,在建立冗余索引来支持覆盖索引时就需要权衡考虑了。这正是业务DBA,或者称为业务数据架构师的工作。 2.4 最左前缀原则看到这里你一定有一个疑问,如果为每一种查询都设计一个索引,索引是不是太多了。如果我现在要按照市民的身份证号去查他的家庭地址呢?虽然这个查询需求在业务中出现的概率不高,但总不能让它走全表扫描吧?反过来说,单独为一个不频繁的请求创建一个(身份证号,地址)的索引又感觉有点浪费。应该怎么做呢? 这里,我先和你说结论吧。B+树这种索引结构,可以利用索引的“最左前缀”,来定位记录。 为了直观地说明这个概念,我们用(name,age)这个联合索引来分析。 当你的逻辑需求是查到所有名字是“张三”的人时,可以快速定位到ID4,然后向后遍历得到所有需要的结果。 如果你要查的是所有名字第一个字是“张”的人,你的SQL语句的条件是"where name like ‘张%’"。这时,你也能够用上这个索引,查找到第一个符合条件的记录是ID3,然后向后遍历,直到不满足条件为止。 可以看到,不只是索引的全部定义,只要满足最左前缀,就可以利用索引来加速检索。这个最左前缀可以是联合索引的最左N个字段,也可以是字符串索引的最左M个字符。 基于上面对最左前缀索引的说明,我们来讨论一个问题:在建立联合索引的时候,如何安排索引内的字段顺序。 这里我们的评估标准是,索引的复用能力。因为可以支持最左前缀,所以当已经有了(a,b)这个联合索引后,一般就不需要单独在a上建立索引了。因此,第一原则是,如果通过调整顺序,可以少维护一个索引,那么这个顺序往往就是需要优先考虑采用的。 所以现在你知道了,这段开头的问题里,我们要为高频请求创建(身份证号,姓名)这个联合索引,并用这个索引支持“根据身份证号查询地址”的需求。 那么,如果既有联合查询,又有基于a、b各自的查询呢?查询条件里面只有b的语句,是无法使用(a,b)这个联合索引的,这时候你不得不维护另外一个索引,也就是说你需要同时维护(a,b)、(b) 这两个索引。 这时候,我们要考虑的原则就是空间了。比如上面这个市民表的情况,name字段是比age字段大的 ,那我就建议你创建一个(name,age)的联合索引和一个(age)的单字段索引。 2.5 索引下推上一段我们说到满足最左前缀原则的时候,最左前缀可以用于在索引中定位记录。这时,你可能要问,那些不符合最左前缀的部分,会怎么样呢? 我们还是以市民表的联合索引(name, age)为例。如果现在有一个需求:检索出表中“名字第一个字是张,而且年龄是10岁的所有男孩”。那么,SQL语句是这么写的:
你已经知道了前缀索引规则,所以这个语句在搜索索引树的时候,只能用 “张”,找到第一个满足条件的记录ID3。当然,这还不错,总比全表扫描要好。然后呢?当然是判断其他条件是否满足。在MySQL 5.6之前,只能从ID3开始一个个回表。到主键索引上找出数据行,再对比字段值。而MySQL 5.6 引入的索引下推优化(index condition pushdown), 可以在索引遍历过程中,对索引中包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表次数。图3和图4,是这两个过程的执行流程图。 图3中,在(name,age)索引里面我特意去掉了age的值,这个过程InnoDB并不会去看age的值,只是按顺序把“name第一个字是’张’”的记录一条条取出来回表。因此,需要回表4次。 图4跟图3的区别是,InnoDB在(name,age)索引内部就判断了age是否等于10,对于不等于10的记录,直接判断并跳过。在我们的这个例子中,只需要对ID4、ID5这两条记录回表取数据判断,就只需要回表2次。 2.6 聚簇索引和非聚簇索引聚簇是为了提高某个属性(或属性组)的查询速度,把这个或这些属性(称为聚簇码)上具有相同值的元组集中存放在连续的物理块。 非聚簇索引:数据和索引是分开的,B+树叶子节点存放的不是数据表的行记录。 虽然InnoDB和MyISAM存储引擎都默认使用B+树结构存储索引,但是只有InnoDB的主键索引才是聚簇索引,InnoDB中的辅助索引以及MyISAM使用的都是非聚簇索引。每张表最多只能拥有一个聚簇索引。 拓展:聚簇索引优缺点? 缺点: 主键索引和普通索引的区别:主键索引只要搜索ID这个B+Tree即可拿到数据。普通索引先搜索索引拿到主键值,再到主键索引树搜索一次(回表) 2.7 为什么建议Innodb表必须建主键,并且推荐使用整形的自增主键?如果不建立主键mysql会帮助我们的表的每一列的每一行排查看是否存在不重复的数据并将其设置成主键。如果没有找到mysql会帮助我自己添加一列自增数据并将其设置成主键,这种做法无疑增加了mysql的压力,降低系统性能。整型比较的速度快,占用内存小自增?以B+树为例,索引数据都存放在叶子节点,而且叶子节点都是有序的,自增这就意味着每次插入的索引数据是从最后面的一个叶子节点插入,即使是分裂也分裂的比较规整。不自增分裂要调整平衡,性能下降。 总结索引是占据物理空间的,在不同的存储引擎中,索引存在的文件也不同。存储引擎是基于表的,以下分别使用MyISAM和InnoDB存储引擎建立两张表。innodb: .frm(表结构) .idb(数据文件 + 索引文件) myisam: .frm(表结构) .myi(索引文件) .myd(数据文件) 主键索引的叶子节点存的是整行数据。在InnoDB里,主键索引也被称为聚簇索引(clustered index)。 如果语句是select * from T where ID=500,即主键查询方式,则只需要搜索ID这棵B+树; 回表:当根据普通索引查询到聚簇索引的key值之后,再根据key值在聚簇索引中获取所有记录。回到主键索引树搜索的过程,我们称为回表 主键长度越小,普通索引的叶子节点就越小,普通索引占用的空间也就越小。 |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 13:22:25- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |