MySQL数据库索引及调优

本文深入探讨了MySQL数据库的索引原理,包括二叉树、红黑树、Hash表和B-Tree/B+Tree数据结构。重点讲解了B+Tree在InnoDB引擎中的应用,强调了其在聚集索引和非聚集索引中的优势。同时,文章提到了联合索引的创建和使用策略,并通过实例展示了如何优化SQL查询以充分利用索引。
摘要由CSDN通过智能技术生成

MySQL数据库索引及调优

1、概述:

索引是对数据库表中一个或多个列的值进行排序的结构。

索引的数据结构:

  • 二叉树
  • 红黑树
  • Hash表
  • B-Tree

MySQL底层是用B+Tree。

数据结构模拟器网站:https://www.cs.usfca.edu/~galles/visualization/Algorithms.html

对于以下数据:
在这里插入图片描述

select * from table where Col1=6

二叉树

二叉树的右侧节点比左侧节点大,构建的索引如下:
在这里插入图片描述
这样去查和去扫描表的效率其实都差不多(扫描表和索引都需要6次)。

红黑树

在这里插入图片描述
红黑树往里面插入元素时,它会自动平衡、进行旋转(红黑树也可以称为二叉平衡树)。执行上面的sql用索引就只需要3次。这样比二叉树要好一点,但是当我们数据量比较大时(例如有500W数据,这样红黑树的层高可能有20层),红黑树的层很高,如果我们查询的数据在最下层,也需要查询20次,效率还是不高。

hash

  • 对索引的key进行一次hash计算就可以定位出数据存储的位置
  • 很多时候hash索引要比B+树索引更高效(如where name='jack’只需要做一次hash就可以找到,有相同的则会依次遍历链表)
  • 仅能满足“=”、“IN”,不支持范围查询(如where name>‘jack’,这种查询hash索引是没有用的)
  • hash冲突问题(哈希冲突:数据量较多时,通过哈希函数产生的哈希值是有限的,还是有很多不同的数据对应相同的哈希值)

B-Tree(高度控制在小的情况下能存大量的数据)

  • 叶节点具有相同的深度,叶节点的指针为空

  • 所有索引元素不重复

  • 节点中的数据索引从左到右递增排列

    如下是一颗B-Tree(图中Max.Degree为区间最大存放元素个数减一):
    在这里插入图片描述

B+Tree

  • 所有数据都在叶子节点上

  • 叶子节点有顺序访问指针
    在这里插入图片描述

B-Tree和B+Tree的区别(都是从左到右依次排好序的)

1、B-Tree的data存在各个节点上,而B+Tree的data只存在叶子节点上,对于每个分层(16k)来限制的话,每一层B+Tree就能存更多的索引,这个样树的高度就能更低,查找的效率就更高。

2、B+Tree的叶子节点之间是有文件访问区间的指针的,这样对于范围查找就可以依次向后遍历;但对于B-Tree来说,如果出现断层,则又要从最上层开始查找。

B+Trees(B-Tree的升级)

  • 非叶子节点不存储data,值存储索引(冗余),可以放更多的索引
  • 叶子节点包含所有索引字段
  • 叶子节点用指针连接,提高区间访问的性能

如下是一颗B+Trees:
在这里插入图片描述

2、InnoDB索引实现(聚集)

两个不同的存储引擎:

InnoDB:数据跟索引放在一个文件里(聚集索引和非聚集索引都可以有,非聚集索引存放的是聚集索引的key值,查找时找key再回表)

myisam:数据和索引分开在不同的文件(所以只有非聚集索引)

表数据文件本身就是按B+Tree组织的一个索引文件

聚集索引

叶节点包含了完整的数据记录(既有索引,又有索引所在行的所有数据,相对于非聚集索引:非聚集索引的索引和数据是在不同的文件)

为什么建议InnoDB表必须建主键,并且推荐使用整型的自增主键

​ 1、当建表不设主键时:InnoDB方式,索引和数据是存在一起的,所以必须要有主键来维护B+Tree的树形结构。没有主键时,MySQL会选取一个不重复的列来作为主键维护B+Tree来存储,如果全部不重复,就会使用rowid的隐藏列来维护B+Tree。所以推荐来建主键,不用交给MySQL来帮我们做。

​ 2、整型数据肯定比字符串查找比对速度更快,且整型存储更节约空间。

​ 3、使用递增,则叶子节点会一直往后添加数据;如果不是,则会先找到该节点的位置,导致该节点分裂,再提到上层,插入的效率就变低,对于高并发来说影响更大。

为什么非主键索引(二级索引)结构叶子节点存储的是主键值(一致性和节省存储空间)

二级索引的索引值为主键索引的值,查询到二级索引的值后回表再找到对应主键对应的所有字段,二级索引和数据data是没有存在一起的,故也是一个非聚集索引
在这里插入图片描述

联合(复合)索引

我们很少在一个表中建多个单值索引,索引是需要占空间的,每次插入的时候都需要维护索引树,推荐建一两个联合索引。

比如说有以下的联合索引,三个字段name、age、position则会按照从左到右依次排序来建立索引。
在这里插入图片描述
当我们跳过前面的索引去查询的时候是不会用到索引的(符合最左原则)。如下:

where name=‘Bill’ and age=31 (会用到索引)

where age=30 and position=‘dev’ (不会用到索引)

where position=‘manage’ (不会用到索引)

案例

案例1

SELECT * FROM table WHERE a = 1 and b = 2 and c = 3;

(a,b,c)或者(c,b,a)或者(b,a,c)都可以,重点要的是将区分度高的字段放在前面,区分度低的字段放后面。像性别、状态这种字段区分度就很低,我们一般放后面。例如假设区分度由大到小为b,a,c。那么我们就对(b,a,c)建立索引。在执行sql的时候,优化器会 帮我们调整where后a,b,c的顺序,让我们用上索引。

案例2

SELECT * FROM table WHERE a > 1 and b = 2;

对(b,a)建立索引。如果你建立的是(a,b)索引,那么只有a字段能用得上索引,毕竟最左匹配原则遇到范围查询就停止匹配。 如果对(b,a)建立索引那么两个字段都能用上,优化器会帮我们调整where后a,b的顺序,让我们用上索引。

案例3

SELECT * FROM table WHERE a > 1 and b = 2 and c > 3;

(b,a)或者(b,c)都可以,要结合具体情况具体分析,a和c看区分度。

案例4

SELECT * FROM table WHERE a = 1 ORDER BY b;

对(a,b)建索引,当a = 1的时候,b相对有序,可以避免再次排序!

SELECT * FROM table WHERE a > 1 ORDER BY b;

对(a)建立索引,因为a的值是一个范围,这个范围内b值是无序的,没有必要对(a,b)建立索引。

案例5

SELECT * FROM table WHERE a IN (1,2,3) and b > 1;

还是对(a,b)建立索引,因为IN在这里可以视为等值引用,不会中止索引匹配,所以还是(a,b)!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值