一、什么是索引?
在关系数据库中,索引是一种单独的对数据表中一列或多列进行排序的一种存储结构,它是某个表中一列或若干列值的集合和相应的指向表中物理标识这些值的逻辑指针清单。
其实就相当于图书的目录,可以根据目录很快找到所需的内容
二、为什么使用索引?
其实就是为了加快数据库中数据的访问速度
三、使用索引为什么可以加快访问速度?
1、mysql查询数据的性能瓶颈在哪里?
mysql的表数据都是存储在磁盘中的,在使用时要将数据从磁盘加载到内存中。因此IO操作就是查询性能瓶颈
2、去磁盘取数据,是用多少取多少?
不是,磁盘和内存交互的最小逻辑单位是页(dataPage),内存每次会从磁盘读取一个或整数倍个页,这叫做磁盘预读。
页的大小是操作系统决定的,一般是4k或8k,innoDB引擎每次读取数据大小为16k
tips:磁盘预读背后的原理是——局部性原理
时间局部性:指的是同一个内存位置,从时间维度看来,它如果被引用了一次,那么较短时间内有很大可能被再次引用
空间局部性:指的是同一个内存位置,从空间维度看来,它如果被引用了一次,那么它附近的内存很大可能会被引用
3、索引什么时候加载到内存?
索引存储在磁盘中,查询数据的时候会优先将索引加载到内存中
4、索引会存储哪些信息?
首先要明白,索引也是一张表,该表保存了主键与索引字段,并指向实体表的记录(真正的表数据)
5、为什么索引的数据结构不采用Hash表?
首先若用Hash表存储的话,Key是索引值,Value是对应的表记录。
- 哈希冲突会造成数据散列不均匀,导致大量的线性查询,浪费时间
- Hash表结构不支持范围查询,当进行范围查询时必须依次遍历
- 对内存空间的要求比较高,因为要将索引表全部加载到内存
但是也不是全无好处,Hash表结构的索引在等值查询的时候是非常快的
在Mysql里面有没有Hash索引?
① memory引擎使用的hash索引
② innoDB引擎支持自适应hash索引
6、为什么Mysql不用BST存储索引?
BST:二叉搜索树,每个节点的左子树上的值都小于该结点值,每个节点的右子树上的值都大于该结点值。
基于这个规律,我们可以使用二分查找法提高查询效率。但是设想这样一种情况:
一张表的数据整体呈递增或递减,那么二叉搜索树就会退化成链表,即线性查询了
7、为什么Mysql不用AVL存储索引?
AVL:平衡二叉树,最短子树和最长子树高度之差不能超过1
前面说了为啥不用BST,那么AVL其实解决了BST的退化问题,但是为了保持树的平衡性,在插入数据时,必须进行左旋或右旋。本质上,这种方案是用插入性能的损失来换取查询性能的提升
若业务是读的需求比写的需求多,这种结构有一定优势,若读写一样多呢?
解:红黑树
8、为什么Mysql不用红黑树存储?
红黑树:一种自平衡的二叉查找树,是一种高效的查找树
- 每个节点要么是红的要么是黑的
- 根节点是必须是黑的
- 每个叶节点(叶节点即指树尾端NIL指针或者NULL节点)必须都是黑的
- 如果一个节点是红的,那么它的两个子节点都是黑的
- 对于任意节点而言,其到叶节点树尾端NIL指针的每条路径都包含相同数目的黑节点
上面5条性质保证了红黑树最长子树不会超过最短子树的两倍,减少了旋转的次数,也保证了一定的平衡性,本质上是查询性能和插入性能的一种折中的方案
但其实还是会存在问题——随着数据的增多,树的深度也随之增加,即意味着IO次数变多,性能降低
9、Mysql为什么不用B树存储索引?
B树:是一种平衡的多路查找树
B树的性质:
1.根结点至少有两个子女。
2.每个中间节点都包含k-1个元素和k个孩子,其中 ceil(m/2) ≤ k ≤ m
3.每一个叶子节点都包含k-1个元素,其中 ceil(m/2) ≤ k ≤ m
4.所有的叶子结点都位于同一层。
5.每个节点中的元素从小到大排列,节点当中k-1个元素正好是k个孩子包含的元素的值域划分
6.每个结点的结构为:(n,A0,K1,A1,K2,A2,… ,Kn,An)
其中,Ki(1≤i≤n)为关键字,且Ki<Ki+1(1≤i≤n-1)。
Ai(0≤i≤n)为指向子树根结点的指针。且Ai所指子树所有结点中的关键字均小于Ki+1。
n为结点中关键字的个数,满足ceil(m/2)-1≤n≤m-1。
但是我们可以看到,它的每个节点上都存储了数据,假设不计指针的空间,每个key+data的大小为1k,innoDB每次从磁盘取16K的数据,即每次只能取16个key+data,如果随着数据的增加,B树的深度也会增加,IO次数也随着增大。
10、Mysql用B+树存储索引
B+树的特性:
B+树的所有叶子节点都在同一层,且叶子节点之间通过指针连接,形成一个有序链表。这样可以方便进行范围查询。
B+树的非叶子节点只存储索引信息,不存储具体的数据。这样可以减少非叶子节点的大小,提高内存利用率。
这就是B+树在存储索引上比B树有优势的地方,B+树的非叶子结点不存储数据,因此,每页存储的指针和索引就可以更多,B+树就比B树更矮胖,有效的减少了IO次数。并且B+树的叶子节点是双向链表结构,支持随机查询数据。
注意:B+树的层数一般来说3/4层就能够满足大部分的需求了,否则就需要进行分表处理
四、什么是存储引擎?
存储引擎是数据库负责数据存储和检索的组件,它定义了数据如何被存储、组织和访问。
1、Mysql支持哪些存储引擎?
- InnoDB:Mysql默认的存储引擎,支持事务,支持外键、支持全文索引、支持聚簇索引(索引和数据在一个文件中),支持行级锁和表锁等
- MyISAM:不支持事务、不支持外键、支持全文索引、不支持聚簇索引、支持非聚簇索引(索引和数据不再一个文件中)、不支持行级锁,支持表锁,对内存空间要求比较高,查询比innoDB快
- Memory:不支持持久化,所有数据都保存在内存中,不常用
- CSV、Archive、Blackhole、NDB (MySQL Cluster)、Merge、Federated、Example
2、聊聊Mysql默认的innoDB引擎
- 先来看一下Mysql的基本架构:
tips:mysql8.0之后Server层抛弃了缓存
- innoDB必须存在且只能存在一个聚簇索引,为什么?因为如果存在多个聚簇索引,会出现数据冗余(一个聚簇索引对应一份数据),这个聚簇索引的key可以是主键,若是不存在主键,那就是唯一键。若不存在唯一键,innoDB会自动生成一个6字节的rowid,作为聚簇索引的key,这个rowid对用户来说是不可见的。下面是官网的解释:
- 什么是回表?
是指通过查询索引获得记录的主键,然后再通过主键查询数据表获取完整的记录的过程,在使用索引查询时,如果查询的字段不在索引中,那么查询结果只包含索引字段,需要通过查询结果中的主键再次查询数据表才能得到完整记录,这个过程就是回表
可以看到,回表操作会增加额外的IO操作,因为需要根据主键再次访问聚簇索引来获取数据,这会导致性能下降。
为了减少回表的次数,可以使用覆盖索引来避免回表操作。覆盖索引是指索引包含了查询所需的所有字段,这样就不需要再通过回表操作来获取数据,从而提高了查询性能
下面举两个例子来说明:
select name,age from User where name=?;
#假设User表在name字段建立了普通索引,那么这个普通索引会指向主键id,然后根据主键id去聚集索引里面查找完整记录,返回。这就叫做回表。
select name,age from User where name = ? and age = ?;
#假设User表在name和age上建立了组合索引,那么查询的字段name和age就被索引全部覆盖了,直接查询这个组合索引就可返回数据,不需要再根据主键去聚集索引查完整记录,这就是覆盖索引
- 设置主键的时候要不要自增?
尽量保持自增,这样在插入数据的时候可以有效减少磁盘块分裂,但自增字段很容易使得数据被爬取,这最终还得取决于业务需求
- 什么是索引下推?
索引下推是一种优化技术,用于在数据库查询中提高性能,它将过滤条件下推到存储引擎层级,减少了磁盘IO操作和数据传输量,由于减少了需要传输的数据量,索引下推还可以减少网络传输的开销。
- 什么是最左匹配?
是指在使用多列索引进行查询时,索引的最左边的列会被优先使用,而后面的列只有在最左边的列相等的情况下才会被使用。
例如:User表的在age字段建立了一个索引
- select * from User where age = ? and name = ?; //生效
- select * from User where name = ? and age = ?;//生效 InnoDB引擎优化会改变顺序
- select * from User where age = ?; //生效
- select * from User where name = ?;//失效
tips:组合索引的结构就是二元组