MySQL-索引详解

目录

一、索引优缺点

二、设计索引

2.1、索引底层结构

三、索引分类

3.1、普通索引 

3.2、唯一性索引

3.3、主键索引

3.4、单列索引

3.5、多列(组合、联合)索引

3.6、全文索引

3.7、聚簇索引

3.8、二级索引(辅助索引、非聚簇索引)

四、InnoDB的B+树索引注意事项

4.1、根页面位置万年不动

4.2、内节点中目录项记录的唯一性

4.3、一个页面最少存储2条记录

五、MyISAM索引原理

5.1、myisam与Innodb的区别:

5.2、总结

六、其他数据结构

6.1、全表遍历

6.2、Hash结构

6.3、二叉搜索树

6.4、AVL平衡二叉搜索树

6.5、B-Tree多路平衡查找树

七、区、段、碎片区

7.1、区

7.2、段

7.3、零散区

7.4、区的分类

7.5、表空间


一、索引优缺点

  • 优点:降低数据库的IO成本;唯一索引可以保证数据库每一行数据的唯一性;加速表与表之间的连接;使用分组和排序是进行查询可以减少查询中分组和排序的时间
  • 缺点:创建和维护索引需要消耗时间;索引占用磁盘空间;虽然增加查询速度,但是会降低更新表的速度,比如删除字段。

二、设计索引

2.1、索引底层结构

简化行格式示意图:

  • record_type:记录头信息的一项属性,表示记录的类型,2表示最小记录、3表示最大记录、1表示目录页。
  • next_record:记录头信息的一项属性,表示下一条地址相对于本条记录的地址偏移量。

数据页中示意图:

磁盘与内存交互的基本单位。

  • 溢出列:由于每个页的大小是16kb,当一个字段存储数值大于这些是,该行记录会记录该数据的一部分,这部分称为溢出页,然后将其他数据存放在其他页中,在本行生成一个20字节的地址指向那些其他数据页,该列称为溢出列。
  • 页分裂:当前页存满时,重新分配下一页,或者主键连续递增时,增加一个中间值的主键,通过记录移动来保证下一个数据页中用户记录的主键值必须大于上一页。
  • 目录项:由于主键递增,所以在增加数据时会出现页分裂情况,页与页之间通过双向链表形式链接,但是查找具体数据时依旧不确定该数据项在哪个数据页中,所以需要将所有数据页设置目录项,记录数据页的最小值和对应的数据页地址。

  • 目录项记录的页:在对数据页进行删除和插入操作时,对应目录项需要删除,除此之外后面的目录项需要前移,成本高,这时可以把目录项再构成目录项记录的页。

  • 更高级的目录:由于数据不断的增加,目录项记录的页达到一定存储大小时会生成新的目录项记录的页,此时查找数据可能会出现3次的IO,这时可以将多个目录项记录的页再次生成一个更高级的目录。

  • 该模型为B+树,一般情况下不会超过4层,层数越小IO次数越小。实际开发中数据页存储16kb大小的数据,层数增加以指数的形式叠加,所以4层存储足够大的数据。

2、索引的设计原则

适合创建索引:

  • 字段的数值有唯一性的限制,即使该字段是组合字段也必须建成唯一索引
  • 频繁的作为where查询条件的字段
  • 经常group by、order by的列,因为索引数据页中的数据是按照顺序连接存储的
  • update、delete的where条件列
  • distinct字段需要创建索引
  • 对于join连接的where条件和连接字段创建索引,join连接的表尽量不要超过3张表,连接的字段类型必须一致,否则会涉及到函数转换导致索引失效
  • 使用列的类型小的创建索引
  • 使用字符串前缀创建索引,节点时占用空间小
  • 区分度高(散列性高)的列适合作为索引,重复性强,计算区分度:select count(distinct a)/count(*) from t1
  • 使用最频繁的列放到联合索引的左侧,增加联合索引的使用次数
  • 多个字段都需要创建索引的情况下,联合索引优于单个索引

不适合创建索引:

  • where中使用不到的字段
  • 数据量小的表最好不使用索引
  • 有大量重复数据的列
  • 避免对经常更新的表创建过多的索引
  • 不建议使用无序的值作为索引
  • 删除不再使用或者使用的索引
  • 不要定义冗余或重复索引,例如:将联合索引的第一个字段定义成一个普通索引

限制索引数目:

  • 每个索引都需要磁盘空间;
  • 优化器执行时会对索引进行则优,索引过多会影响优化器生成执行计划的时间
  • 索引会影响insert、update、delete等语句的性能,表中数据进行更改时,索引会对数据进行调整和更新,会造成负担

三、索引分类

MySQL的索引包括普通索引、唯一性索引、全文索引、单列索引、多列索引和空间索引等。

  • 从功能逻辑上分:普通索引、唯一索引、主键索引、全文索引
  • 从物理实现方式分:聚簇索引、非聚簇索引
  • 从作用字段上来分:单列索引、联合索引

3.1、普通索引 

不附加任何条件,可以创建在任何数据类型中,对空和唯一没有要求。

3.2、唯一性索引

凡是声明UNIQUE参数都会自动生成一个唯一性索引。

3.3、主键索引

主键约束自动生成主键索引,也是聚簇索引,只能有一个,决定底层物理实现方式。

3.4、单列索引

在表中的单个字段上创建的索引,可以是唯一索引、全文索引,只要保证该索引只对应一个字段即可。

3.5、多列(组合、联合)索引

使用多个列的大小作为排序规则,比如为c1,c2创建一个联合索引,会先把各个记录和页按照c1进行排序,在c1相同的情况下按照c2进行排序

叶子节点由联合索引的字段数据和主键字段数据构成,也具有回表操作。使用时遵循最左前缀原则。

3.6、全文索引

搜索引擎使用关键技术,可以分析出文本文字中关键词的频率和重要性然后按照算法筛选出想要的搜索结果。FULLTEXT可以设置全文索引,只能创建在CHAR、VARCHAR或TEXT字段上,查询数据量较大的字符串类型字段时可以使用全文索引

3.7、聚簇索引

由主键构成的索引,一种数据存储方式,所有用户记录都存储在叶子节点,索引即数据,数据即索引。上面的例子就是聚簇索引结构。

  • B+树的叶子节点存储的是完整的用户记录。
  • 使用主键值的大小进行记录和页的排序
  • 页与页之间形成的是双向链表
  • 即使自己不创建,innodb也会自动创建

优点:

  • 数据访问快,索引和数据保存在同一个B+树中,获取数据比非聚簇索引快
  • 排序查找和范围查找快
  • 节省大量IO操作

缺点

  • 插入速度依赖于插入顺序
  • 更新主键代价高
  • 二级索引访问需要两次索引查找,第一次查找主键值,第二次查找行数据

补充

  • MyISAM不支持聚簇索引
  • 数据物理排序只能有一种方式,所以每个MySQL只能有一个聚簇索引,一般情况下是该表的主键
  • 如果没有定义主键,innodb会自动选择一个非空的唯一索引代替,如果没有该索引,会隐式定义一个主键来作为聚簇索引
  • 为了充分利用聚簇索引特性,Innodb表主键列尽量选用有序的顺序id,不建议使用无序、加密、字符串等列作为主键

3.8、二级索引(辅助索引、非聚簇索引)

一个表中只能有一个聚簇索引但是可以有多个二级索引,二级索引进行插入、删除、更新操作时比聚簇索引效率高

  • 二级索引叶子节点只存储该索引字段下的值和主键的值,不建议存储其他字段,在可以设置多个二级索引的情况下,存储过多字段对空间进行浪费,会降低性能
  • 二级索引除了该字段查找数据快速外,更大的作用是帮助其他字段对应的主键然后通过回表进行数据的查找
  • 回表:此时如果查找其他字段,那么需要通过二级索引查找到对应的主键,重新再通过聚簇索引查找该主键下的其他字段值

四、InnoDB的B+树索引注意事项

4.1、根页面位置万年不动

当为某个表创建一个B+树索引时,会为这个索引创建一个根页面,此时没有目录项,根节点也没有用户记录。当插入一条数据时会先向根节点中增加,当根节点达到存储最大值时,会将该根节点数据复制到一个新的页,对这个页进行页分裂,得到新的页,插入的数据键值会存储到该页中,此时根节点升级为存储目录项记录的页。

4.2、内节点中目录项记录的唯一性

主要针对二级索引,目录项记录存储该索引的字段加主键加页号组成,没有主键的话索引字段可能会存在相同数值情况,无法向下进行查询,加入主键后在索引字段相同时,可以再查询主键,根据主键继续向下查询。

4.3、一个页面最少存储2条记录

五、MyISAM索引原理

在innodb中索引即数据,MyISAM中索引和数据是分开存储的,Innodb中数据页存储的是主键值+数据,MyISAM中存放的数数据记录的地址。

5.1、myisam与Innodb的区别:

  • Innodb中聚簇索引进行一次查找就可以获得数据,myisam中需要进行回表,可以认为myisam中索引全部都是二级索引。
  • innodb中索引即数据,myisam中索引和数据分在不同文件中存储,.myd和.myi
  • innodb数据页存储着主键值,myisam存储的是地址
  • myisam回表操作十分快速,直接拿地址进行回表,innodb是拿着主键进行回表
  • innodb必须有主键,没有会拿一个非空唯一值作为主键,即使没有也会自动生成一个隐式主键,myisam可以没有

5.2、总结

  • 不建议使用过长字段作为主键,因为所有二级索引都引用主键,主键过长会导致二级索引过大
  • 使用自增字段作为主键,维护方便

六、其他数据结构

6.1、全表遍历

6.2、Hash结构

  • Hash算法可以保证相同输入永远可以得到相同输出。
  • 加速查找数据的数据结构,常见的有两类:

树,例如平衡二叉搜索树,查询、插入、修改、删除的平均时间复杂度都是O(log2N);

哈希,例如HashMap,查询、插入、修改、三处的平均时间复杂度都是O(1)

  • 从效率上来说Hash比B+树快,但是Hash范围查找需要进行计算,适用于等值查找;数据存储是无序的,排序无法使用Hash特征;联合索引时Hash是合并一起计算,无法对单独一个或者几个索引进行查询;对于重复值比较多的列,会去遍历链表降低效率;innodb不支持此索引但支持自适应Hash索引、myisam不支持该结构,Memory支持;适用于Redis。

6.3、二叉搜索树

特点:

  • 一个节点只能有两个子节点
  • 左子节点<本节点;右子节点>=本节点,比我大的向右,比我小的向左

查找规则:

  • 大于根节点,在右子树中查找
  • 小于根节点,在左子树中查找
  • 等于根节点,返回根节点

6.4、AVL平衡二叉搜索树

在一个有序的数据中使用二叉搜索树会形成一条链表,查找数据的时间复杂度变成了O(n)。此时需要平衡二叉搜索树。ee60f72707ef886f5bc5e13d62feac2e.png

常见平衡二叉树:红黑树、数堆、伸展树、平衡二叉搜索树。24e320dd80a9a833d277b5001b934f64.png

6.5、B-Tree多路平衡查找树

p1、p2、p3为指针,数据小于此范围则走p1,数据在此范围则走p2,数据大于此范围则走p3。

B树和B+树的差异:

  • B+树有k个关键字就有k个节点,B-Tree有k个关键字则有k+1个节点;
  • B+树中非叶子节点的关键字同时也会存在叶子结点中,并且在子节点中所有关键字的最大(或最小);
  • B+树中非叶子节点仅用于索引,不保存数据记录,有关的数据记录都存放在叶子节点中。B-Tree中非叶子节点也存放索引和具体数据;
  • 所有关键字都在叶子节点中按照关键字大小有序连接;
  • B+树查询效率更稳定,B树查找的数据可能在叶子节点上也可能在非叶子节点上;
  • 范围查询时,B+树更快,非叶子节点链表形式更方便,B树需要回溯树查找。

七、区、段、碎片区

7.1、区

每个页距离可能很远,巡道时间长,出现随机IO,速度慢,建议使用顺序IO,所以需要让页顺序存储。一个区就是连续的64个页,一个区为1M大小,区与区之间可能不是连续的。

7.2、段

存放叶子节点和非叶子节点,进行分类成段,常见的段有数据段、索引段、回滚段。是一个逻辑上的概念,不是一个连续的物理区域,是一个零散的页面。

7.3、零散区

当叶子节点成为一个区、非叶子节点成为一个区,此时会出现2m大小的区,当数据量没这么大的时候,会造成空间浪费,因此出现碎片区,碎片区的页可以用来不同场景,很好的利用剩余空间

为某一个段分配存储空间策略:

  • 刚开始像表中插入数据时,段是从某个碎片区以单个页面为单位来分配存储空间的
  • 当某个段已经占用32个碎片区页面之后,就会申请以完整的区为单位来分配存储空间

7.4、区的分类

  • 空闲的区:现在还没有用到这个区的任何页面
  • 有剩余空间的碎片区:表示碎片区中还有可用的页面
  • 没有剩余空间的碎片区:表示碎片区中的所有页面都被使用,没有空闲的页面
  • 附属与某个段的区:每一个索引都可以分为叶子结点段和非叶子节点段

7.5、表空间

所有数据都存放在表空间,是Innodb存储引擎逻辑结构的最高层。

表空间是一个逻辑容器,存储的是段,一个表空间可以存储多个段,一个段只能属于一个表空间。

分类:系统表空间、独立表空间、撤销表空间、临时表空间。

独立表空间:

每张表都有一个独立的表空间,索引和数据都保存在自己表空间,有利于数据迁移和表回收,删除表空间、释放表空间比较方便。

mysql8中.idb文件存储大小为7个页的大小,5.7为6个,8中还需要存储.ifm数据,所以空间大。

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值