美文网首页数据库
mysql索引及类型

mysql索引及类型

作者: hellokitty小丸子 | 来源:发表于2021-08-02 14:26 被阅读0次

    一、什么是mysql索引?

    打个比方,如果合理的设计且使用索引的MySQL是一辆兰博基尼的话,那么没有设计和使用索引的MySQL就是一个人力三轮车。拿汉语字典的目录页(索引)打比方,我们可以按拼音、笔画、偏旁部首等排序的目录(索引)快速查找到需要的字。
    实际上,索引也是一张表,该表保存了主键与索引字段,并指向实体表的记录。

    二、索引有什么优点?

    MySQL索引的建立对于MySQL的高效运行是很重要的,索引可以大大提高MySQL的检索速度。创建索引时,你需要确保该索引是应用在 SQL 查询语句的条件(一般作为 WHERE 子句的条件)。

    三、索引有什么缺点?

    上面都在说使用索引的好处,但过多的使用索引将会造成滥用。因此索引也会有它的缺点:虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件。

    四、索引有什么类型?

    Normal、Unique、FullText、Spatial,本文主要讲常用的Normal、Unique。


    索引类型.png
    Normal 普通索引:

    表示普通索引,大多数情况下都可以使用

    Unique 唯一索引

    表示唯一的,不允许重复的索引,如果该字段信息保证不会重复,例如:身份证号用作索引时,可设置为unique。其中有一个特殊的唯一索引,我们也称之为“主键索引”。
    Unique(要求列唯一),Primary Key(primary key = unique + not null)。Primary Key是拥有自动定义的Unique约束,但是每个表中可以有多个Unique约束,但是只能有一个Primary Key约束。

    FullText 全文索引

    表示全文收索,用于搜索很长一篇文章的时候,效果最好。用在比较短的文本,如果就一两行字的,普通的 INDEX 也可以。

    Spatial 空间索引

    空间索引是对空间数据类型的字段建立的索引,MYSQL中的空间数据类型有4种,分别是GEOMETRY、POINT、LINESTRING、POLYGON。MYSQL使用SPATIAL关键字进行扩展,使得能够用于创建正规索引类型的语法创建空间索引。创建空间索引的列,必须将其声明为NOT NULL,空间索引只能在存储引擎为MYISAM的表中创建。

    五、索引有什么方法?

    1、Btree索引结果及原理:

    说到Btree索引不得不提聚集索引和非聚集索引了:
    在 MySQL 中,B+ 树索引按照存储方式的不同分为聚集索引和非聚集索引。这里我们着重介绍 InnoDB 中的聚集索引和非聚集索引:
    ①聚集索引(聚簇索引):以 InnoDB 作为存储引擎的表,表中的数据都会有一个主键,即使你不创建主键,系统也会帮你创建一个隐式的主键。
    这是因为 InnoDB 是把数据存放在 B+ 树中的,而 B+ 树的键值就是主键,在 B+ 树的叶子节点中,存储了表中所有的数据。这种以主键作为 B+ 树索引的键值而构建的 B+ 树索引,我们称之为聚集索引。
    ②非聚集索引(非聚簇索引):以主键以外的列值作为键值构建的 B+ 树索引,我们称之为非聚集索引。
    非聚集索引与聚集索引的区别在于非聚集索引的叶子节点不存储表中的数据,而是存储该列对应的主键,想要查找数据我们还需要根据主键再去聚集索引中进行查找。这个再根据聚集索引查找数据的过程,我们称为回表。

    聚集索引和非聚集索引的联系与区别:

    一张表可以存在多个非聚集(辅助)索引,但是只能有一个聚集索引,通过辅助索引来查找对应的行记录的话,需要进行两步,第一步通过辅助索引来确定对应的主键,第二步通过相应的主键值在聚簇索引中查询到对应的行记录,也就是进行两次B+树搜索。相反通过辅助索引来查询主键的话,遍历一次辅助索引就可以确定主键了,也就是所谓的索引覆盖,不用回表(查询聚集索引)。
    明白了聚集索引和非聚集索引的定义,我们应该明白这样一句话:数据即索引,索引即数据。
    下面我们通过讲解如何通过聚集索引以及非聚集索引查找数据表中数据的方式介绍一下 B+ 树索引查找数据方法:

    利用聚集索引查找数据:
    聚集索引.png

    还是这张 B+ 树索引图,现在我们应该知道这就是聚集索引,表中的数据存储在其中。

    select * from user where id>=18 and id <40
    
    其中 id 为主键,具体的查找过程如下: 查找过程.png

    ①一般根节点都是常驻内存的,也就是说页 1 已经在内存中了,此时不需要到磁盘中读取数据,直接从内存中读取即可。
    从内存中读取到页 1,要查找这个 id>=18 and id <40 或者范围值,我们首先需要找到 id=18 的键值。
    从页 1 中我们可以找到键值 18,此时我们需要根据指针 p2,定位到页 3。
    ②要从页 3 中查找数据,我们就需要拿着 p2 指针去磁盘中进行读取页 3。
    从磁盘中读取页 3 后将页 3 放入内存中,然后进行查找,我们可以找到键值 18,然后再拿到页 3 中的指针 p1,定位到页 8。
    ③同样的页 8 页不在内存中,我们需要再去磁盘中将页 8 读取到内存中。
    将页 8 读取到内存中后。因为页中的数据是链表进行连接的,而且键值是按照顺序存放的,此时可以根据二分查找法定位到键值 18。
    此时因为已经到数据页了,此时我们已经找到一条满足条件的数据了,就是键值 18 对应的数据。
    因为是范围查找,而且此时所有的数据又都存在叶子节点,并且是有序排列的,那么我们就可以对页 8 中的键值依次进行遍历查找并匹配满足条件的数据。
    我们可以一直找到键值为 22 的数据,然后页 8 中就没有数据了,此时我们需要拿着页 8 中的 p 指针去读取页 9 中的数据。
    ④因为页 9 不在内存中,就又会加载页 9 到内存中,并通过和页 8 中一样的方式进行数据的查找,直到将页 12 加载到内存中,发现 41 大于 40,此时不满足条件。那么查找到此终止。

    利用非聚集索引查找数据:
    非聚集索引.png

    在叶子节点中,不再存储所有的数据了,存储的是键值和主键。对于叶子节点中的 x-y,比如 1-1。左边的 1 表示的是索引的键值,右边的 1 表示的是主键值。

    select * from user where num=33
    
    查找过程.png

    查找的流程跟聚集索引一样,这里就不详细介绍了。我们最终会找到主键值 47,找到主键后我们需要再到聚集索引中查找具体对应的数据信息,此时又回到了聚集索引的查找流程。

    B+ 树优点:

    因为 B+ 树索引的所有数据均存储在叶子节点,而且数据是按照顺序排列的。
    那么 B+ 树使得范围查找,排序查找,分组查找以及去重查找变得异常简单。
    B+ 树中各个页之间是通过双向链表连接的,叶子节点中的数据是通过单向链表连接的。

    2、HASH(key,value)

    这种方式对范围查询支持得不是很好。
    hash 索引结构的特殊性,其检索效率非常高,索引的检索可以一次定位,不像BTree 索引需要从根节点到枝节点,最后才能访问到叶节点这样多次的IO访问,所以 Hash 索引的查询效率要远高于 BTree 索引。
    可能很多人又有疑问了,既然 Hash 索引的效率要比 BTree 高很多,为什么大家不都用 Hash 索引而还要使用 BTree 索引呢?任何事物都是有两面性的,Hash 索引也一样,虽然 Hash 索引效率高,但是 Hash 索引本身由于其特殊性也带来了很多限制和弊端,主要有以下这些:
    (1)Hash 索引仅仅能满足”=”,”IN”和”<=>”查询,不能使用范围查询。
    由于 Hash 索引比较的是进行 Hash 运算之后的 Hash 值,所以它只能用于等值的过滤,不能用于基于范围的过滤,因为经过相应的 Hash 算法处理之后的 Hash 值的大小关系,并不能保证和Hash运算前完全一样。
    (2)Hash 索引无法被用来避免数据的排序操作:
    由于 Hash 索引中存放的是经过 Hash 计算之后的 Hash 值,而且Hash值的大小关系并不一定和 Hash 运算前的键值完全一样,所以数据库无法利用索引的数据来避免任何排序运算;
    (3)Hash 索引不能利用部分索引键查询:
    对于组合索引,Hash 索引在计算 Hash 值的时候是组合索引键合并后再一起计算 Hash 值,而不是单独计算 Hash 值,所以通过组合索引的前面一个或几个索引键进行查询的时候,Hash 索引也无法被利用。
    (4)Hash 索引在任何时候都不能避免表扫描:
    前面已经知道,Hash 索引是将索引键通过 Hash 运算之后,将 Hash运算结果的 Hash 值和所对应的行指针信息存放于一个 Hash 表中,由于不同索引键存在相同 Hash 值,所以即使取满足某个 Hash 键值的数据的记录条数,也无法从 Hash 索引中直接完成查询,还是要通过访问表中的实际数据进行相应的比较,并得到相应的结果:
    (5)Hash 索引遇到大量Hash值相等的情况,性能不一定就会比BTree索引高:
    对于选择性比较低的索引键,如果创建 Hash 索引,那么将会存在大量记录指针信息存于同一个 Hash 值相关联。这样要定位某一条记录时就会非常麻烦,会浪费多次表数据的访问,而造成整体性能低下。

    六、在实际操作过程中,应该选取表中哪些字段作为索引?

    为了使索引的使用效率更高,在创建索引时,必须考虑在哪些字段上创建索引和创建什么类型的索引,有以下基本原则:

    1.选择唯一性索引

    唯一性索引的值是唯一的,可以更快速的通过该索引来确定某条记录。例如,学生表中学号是具有唯一性的字段。为该字段建立唯一性索引可以很快的确定某个学生的信息。如果使用姓名的话,可能存在同名现象,从而降低查询速度。

    2.为经常需要排序、分组和联合操作的字段建立索引

    经常需要ORDER BY、GROUP BY、DISTINCT和UNION等操作的字段,排序操作会浪费很多时间。如果为其建立索引,可以有效地避免排序操作。

    3.为常作为查询条件的字段建立索引

    如果某个字段经常用来做查询条件,那么该字段的查询速度会影响整个表的查询速度。因此,为这样的字段建立索引,可以提高整个表的查询速度。

    4.限制索引的数目

    索引的数目不是越多越好。每个索引都需要占用磁盘空间,索引越多,需要的磁盘空间就越大。修改表时,对索引的重构和更新很麻烦。越多的索引,会使更新表变得很浪费时间。

    5.尽量使用数据量少的索引

    如果索引的值很长,那么查询的速度会受到影响。例如,对一个CHAR(100)类型的字段进行全文检索需要的时间肯定要比对CHAR(10)类型的字段需要的时间要多。

    6.尽量使用前缀来索引

    如果索引字段的值很长,最好使用值的前缀来索引。例如,TEXT和BLOG类型的字段,进行全文检索会很浪费时间。如果只检索字段的前面的若干个字符,这样可以提高检索速度。

    7.删除不再使用或者很少使用的索引

    表中的数据被大量更新,或者数据的使用方式被改变后,原有的一些索引可能不再需要。数据库管理员应当定期找出这些索引,将它们删除,从而减少索引对更新操作的影响。

    参考资料:
    https://blog.csdn.net/guo_qiangqiang/article/details/88794971
    https://cloud.tencent.com/developer/article/1004912
    https://blog.csdn.net/qq_40951086/article/details/82706862
    https://blog.csdn.net/qq_35571554/article/details/82759668?utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control
    http://www.liuzk.com/410.html

    相关文章

      网友评论

        本文标题:mysql索引及类型

        本文链接:https://www.haomeiwen.com/subject/yfwqvltx.html