MySQL系列 MySQL的索引和算法

Posted wang-kai-1994

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL系列 MySQL的索引和算法相关的知识,希望对你有一定的参考价值。

  • 11 表结构

    • 表是关于特定实体的数据集合,这也是关系型数据库的核心。
    • 在InnoDB中,表都是根据主键顺序组织存放的,这种存储方式的表成为索引组织表。
    • 所有数据都被逻辑的存放在一个空间中,称之为表空间 tablespace。 表空间又由段 segment, 区 extent, 页page 组成。 页在一些文档中有时也称之为块 block。
    • 一个区一般为1M,一个页总是16KB,即一个区一共有64个连续的页。
    • InnoDB中数据是按行进行存放的。每个页存放的行是有硬性规定规定的,最多运行存放16 KB/2-200行数据,即7992行记录。另外也有面向列的数据库,优点是分析类SQL语句的执行及数据压缩是非常有效的。面向列是当前数据库发展的一个方向。
    • 内部是按照一种链表的结构来串连各个行记录的,当前位置的记录加上偏移量就是下条记录的起始地址。
    • 行数据溢出,当行中数据过大时,页中只保留了前786字节的前缀数据,之后是偏移量,指向行溢出页。
  • 12 索引

    • B+树索引

      • 平衡二叉树的左旋和右旋

         技术图片技术图片

         

      • 概述

        B+树是为磁盘或其他直接存取辅助设备设计的一种平衡查找树。

        在B+树中,所有记录节点都是按键值的大小顺序存放在同一层的叶子节点上,由各叶子节点指针进行连接。

        B+树索引在数据库中有一个特点是高扇出性,因此在数据库中,B+树的高度一般都在2~4层,这也就是说查找某一键值的行记录时最多只需要2到4次IO。

        数据库中的B+树索引可以分为聚集索引(clustered inex)和辅助索引(secondary index),但是不管是聚集还是辅助的索引,其内部都是B+树的,即高度平衡的,叶子节点存放着所有的数据。聚集索引与辅助索引不同的是,叶子节点存放的是否是一整行的信息。

      • 聚集索引

        • 聚集索引构造图

           技术图片

        InnoDB 存储引擎表是索引组织表,即表中数据按照主键顺序存放。而聚集索引就是每张表根据主键构造一棵B+树,叶子节点中存放的即为整张表的行记录数据,也将聚集索引的叶子节点称为数据页。

        聚集索引的这个特性决定了索引组织表中数据也是索引的一部分。每个数据页都通过一个双向链表来进行链接。 数据页的排序只能按照一颗B+树进行,这也是每张表只能拥有一个聚集索引的根本原因。

        在多数情况下,查询优化器倾向于采用聚集索引。因为聚集索引能够在B+树索引的叶子节点上直接找到数据。

        此外,由于定义了数据的逻辑顺序,聚集索引能够特别快地访问针对范围值的查询。注:比如查询倒数10个主键元素,数据页是双向链表进行链接的;比如范围查询,查询500-1000的主键元素,主键都是顺序存放的,可以直接按照区间查询。

        数据页上存放的是完整的每行的记录,而在非数据页的索引页中,存放的仅仅是键值及指向数据页的偏移量,而不是一个完整的行记录。

        注:

        • 每张表中有一个聚集索引页和一个或多个辅助索引页,聚集索引页存放的即是每个主键和数据页的映射关系。主键是按照顺序存放,查询时使用二分查找。
        • 数据页的子级单位并不直接是行,而是槽,槽的子级单位才是行。每个数据页中保存一定数量的槽,每个槽中保存4-8个行记录。
        • 通过聚集索引的头节点数据,可以查询到对应的数据页、槽、槽中行记录的偏移量。数据页中保存着行记录的起始和结束位置。每个行记录的头节点又保存着下一个行记录的相对偏移量。
        • 因此通过主键就可以完成一张表的扫描。
        • 聚集索引和非聚集索引实际上是不同的B+树,且聚集索引有且只有一颗B+树,非聚集索引则根据索引的类型分别建立一颗。
      • 辅助索引(非聚集索引)

        • 辅助索引构造图

           技术图片

        对于辅助索引,叶子节点并不包含行记录的全部数据。

        叶子节点除了包含键值以外,每个叶子节点中的索引行中还包含了一个书签

        该书签用来告诉 InnoDB 存储引擎哪里可以找到与索引相对应的行数据。书签存放的即是相应行的聚集索引。

        辅助索引的存在并不影响数据在聚集索引中的组织,因此每张表上可以有多个辅助索引。

        当通过辅助索引来寻找数据时,InnoDB 存储引擎会遍历辅助索引并通过叶级别的指针获得对应的聚集索引,然后再通过聚集索引来找到一个完整的行记录。

        举例来说,如果在一棵高度为3的辅助索引树中查找数据,那需要对这棵辅助索引树遍历3次找到指定聚集索引,如果聚集索引树的高度同样为3,那么还需要对聚集索引树进行3次查找,最终找到一个完整的行数据所在的页,因此一共需要6次逻辑IO访问以得到最终的一个数据页,槽中的查找因为在内存中不算一次IO。

        对于其他的一些数据库,如Microsoft SQL Server数据库,其有一种称为堆表的表类型,即行数据的存储按照插入的顺序存放。堆表的特性决定了堆表上的索引都是非聚集的,主键与非主键的区别只是是否唯一且非空。因此这时书签是一个行标识符,可以用如“文件号:页号:槽号”的格式来定位实际的行数据。

        • 覆盖索引

          从辅助索引上就可以得到所需数据,而不用再通过主键进行索引。

          因为辅助索引存放的索引列和对应的值,以及书签。

        • 联合索引

          • 联合索引结构图

             技术图片

          指对表上的多个列建立索引。

          联合索引是根据第一个索引值进行排序的,因此页适用于第一个索引的查询。比如(a,b),适用于 where a=xx 而不适用于 where b=xx 。

          联合索引的第二个好处是已经对第二个键值进行了排序处理。例如,在很多情况下应用程序都需要查询某个用户的购物情况,并按照时间进行排序,最后取出最近三次的购买记录,这时使用联合索引可以避免多一次的排序操作,因为索引本身在叶子节点已经排序了。

      • OLTP 和 OLAP 中 B+树的使用概述

        在了解了B+树索引的本质和实现后,下一个需要考虑的问题是怎样正确地使用B+树索引。

        在OLTP应用中,查询操作只从数据库中取得一小部分数据,甚至在很多时候只取1条记录,如根据主键值来取得用户信息,根据订单号取得订单的详细信息,这都是典型OLTP应用的查询情况。在这种情况下,B+树索引建立后,对该索引的使用应该只是通过该索引取得表中少部分的数据。这时建立B+树索引才是有意义的,否则即使建立了,优化器也可能选择不使用索引。

        对于OLAP应用,情况可能就稍显复杂了。不过概括来说,在OLAP应用中,都需要访问表中大量的数据,根据这些数据来产生查询的结果,这些查询多是面向分析的查询,目的是为决策者提供支持。如这个月每个用户的消费情况,销售额同比、环比增长的情况。因此在OLAP中索引的添加根据的应该是宏观的信息,而不是微观,因为最终要得到的结果是提供给决策者的。例如不需要在OLAP中对姓名字段进行索引,因为很少需要对单个用户进行查询。但是对于OLAP中的复杂查询,要涉及多张表之间的联接操作,因此索引的添加依然是有部分意义的。

    • 全文索引

      • 概述

        全文检索(Full-Text Search)是将存储于数据库中的整本书或整篇文章中的任意内容信息查找出来的技术。它可以根据需要获得全文中有关章、节、段、句、词等信息,也可以进行各种统计和分析。

      • 倒排索引

        全文检索通常使用倒排索引来实现。倒排索引同B+树索引一样,也是一种索引结构。它在辅助表中存储了单词与单词自身在一个或多个文档中所在位置之间的映射。这通常利用关联数组实现。

        数据的表现形式之一为:

        • full invertedindex,其表现形式为{单词,(单词所在文档的ID,在具体文档中的位置)}

        全文检索的表中,有两个列: word 和 ilist。word上设有索引。

        辅助表:倒排索引中存放 word 字段的物理表

      • 全文检索索引缓存

        全文检索索引缓存采用红黑树结构,根据(word, ilist) 进行排序。

        实现非常复杂,主要目的是为了提供全文索引的缓存,提高全文检索的性能。

    • 哈希索引

      InnoDB存储引擎使用哈希算法来对字典进行查找,其冲突机制采用链表方式,哈希函数采用除法散列方式。

      对于缓冲池页的哈希表来说,在缓冲池中的Page页都有一个chain指针,它指向相同哈希函数值的页。而对于除法散列,m的取值为略大于2倍的缓冲池页数量的质数。例如:当前参数innodb_buffer_pool_size的大小为10M,则共有640个16KB的页。对于缓冲池页内存的哈希表来说,需要分配640×2=1280个槽,但是由于1280不是质数,需要取比1280略大的一个质数,应该是1399,所以在启动时会分配1399个槽的哈希表,用来哈希查询所在缓冲池中的页。

      InnoDB存储引擎的表空间都有一个表ID,用户所要查询的应该是某个表空间的某个连续16KB的页,即偏移量offset。InnoDB存储引擎将space_id左移20位,然后加上这个space_id和offset,即关键字K=space_id<<20+space_id+offset,然后通过除法散列到各个槽中去。

      • 自适应哈希索引 AHI

        InnoDB存储引擎会监控对表上各索引页的查询。如果观察到建立哈希索引可以带来速度提升,则建立哈希索引,称之为自适应哈希索引。

        AHI 是通过缓冲池的B+树页构造而来,因此建立的速度很快,而且不需要对整张表构建哈希索引。InnoDB存储引擎会自动根据访问的频率和模式来自动地为某些热点页建立哈希索引

        自适应哈希索引仅是数据库自身创建并使用的,DBA本身并不能对其进行干预。自适应哈希索引经哈希函数映射到一个哈希表中,因此对于字典类型的查找非常快速,如 where id=1;

        自适应哈希索引建立的条件

        • 对这个页的连续访问模式必须是一样的。
        • 以该模式访问了100次
        • 页通过该模式访问了N次,N=表中记录 * 1/16

        自适应哈希索引的优势

        • 读取和写入速度可以提高2倍
        • 辅助索引的连接操作性能提高5倍

以上是关于MySQL系列 MySQL的索引和算法的主要内容,如果未能解决你的问题,请参考以下文章

Mysql 系列 | 索引(唯一索引 or 普通索引)

五分钟,让你明白MySQL是怎么选择索引《死磕MySQL系列 六》

MySQL系列:索引基本操作

MySQL系列:kafka停止命令

图文动画详解原理系列1.MySQL 索引原理详解

mysql 开发基础系列15 索引的设计和使用