MySQL索引:优化查询性能的利器

Mysql索引

0.写在前面

文章中包含了:

1.什么是索引

2.索引的数据结构,以及各自的使用场景

3.为什么要设置主键自增?

4.基于主键索引和普通索引的查询有什么区别?

5.什么是回表

6.InnoDB 的索引模型

1.为什么要使用索引

索引的使用就是为了提高查询数据的效率,就像书的目录一样

2.常见的索引模型

哈希表

哈希表是一种以键值存储的数据结构,只需要通过key就可以找到对应的值

思路:把值放在数组里,用一个哈希函数把key换算成一个确定的位置,然后把value放在数组的这个位置

当多个key经过哈希函数换算,会出现同一个值,即碰撞,一般通过拉链表解决。
使用哈希表的缺陷是,经过哈希算法算出的位置是随机的,做区间查找就得将表全部扫描

所以哈希表这种结构就适合做等值查询的场景,比如Memcached及其它一些nosql引擎

有序数组

有序数组在等值查询和范围查询中的性能就非常优秀了

但是这也是仅仅对于查询来看,如果要更新的时候,就得挪动后面的记录,成本太高了
所以有序数组只适合用于静态存储索引,也就是那些不在会被修改的历史数据

二叉搜索树

二叉搜索树的特点是:每个节点的左儿子小于父节点,父节点又小于右儿子。这样查找时间复杂度是O(log(n))级别

树可以有二叉,也可以有多叉。多叉树就是每个节点有多个儿子,儿子之间的大小保证从左到右递增。
二叉树是搜索效率最高的,但是实际上大多数的数据库存储却并不使用二叉树。其原因是,索引不止存在内存中,还要写到磁盘上。为了让一个查询尽量少地读磁盘,就必须让查询过程访问尽量少的数据块。那么,我们就不应该使用二叉树,而是要使用"N叉"树。这里,"N叉"树中的"N"取决于数据块的大小。

InnoDB 的索引模型

在InnoDB中,表都是根据主键顺序以索引的形式存放的,这种存储方式的表称为索引组织表。又因为前面我们提到的,InnoDB使用了B+树索引模型,所以数据都是存储在B+树中的。每一个索引在InnoDB里面对应一棵B+树。

  • 假设有一个主键为id的表,字段grade上有索引
css 复制代码
mysql> create table Student(
id int primary key, 
grade int not null, 
name varchar(16),
index (k))engine=InnoDB;

表中t1~t5的(ID,grade)值分别为(1,70)、(2,80)、(3,90)、(4,100)和(5,110),

此时两棵索引树的示例示意图如下。

从图中不难看出,根据叶子节点的内容,索引类型分为主键索引和非主键索引

主键索引的叶子节点存的是整行数据。在InnoDB里,主键索引也被称为聚簇索引(clustered index)。

非主键索引的叶子节点内容是主键的值。在InnoDB里,非主键索引也被称为二级索引(secondary index)。

那么基于主键索引和普通索引的查询有什么区别?

如果语句是select * from T where ID=500,即主键查询方式,则只需要搜索ID这棵B+树;

如果语句是select * from T where k=5,即普通索引查询方式,则需要先搜索k索引树,得到ID的值为500,再到ID索引树搜索一次。这个过程称为回表。

也就是说,基于非主键索引的查询需要多扫描一棵索引树。因此,我们在应用中应该尽量使用主键查询。

3.索引维护

B+树为了维护索引有序性,在插入新值的时候需要做必要的维护。根据b+树的性质,当插入的值比之前的值都大时,只需在末尾加一个就行了,如果新插入的值,在之前插入值的中间,就相对麻烦了,需要逻辑上挪动后面的数据,空出位置。而更糟的情况是,如果最后一个值所在的数据页已经满了,根据B+树的算法,这时候需要申请一个新的数据页,然后挪动部分数据过去。这个过程称为页分裂。在这种情况下,性能自然会受影响。

除了性能外,页分裂操作还影响数据页的利用率。原本放在一个页的数据,现在分到两个页中,整体空间利用率降低大约50%。

当然有分裂就有合并。当相邻两个页由于删除了数据,利用率很低之后,会将数据页做合并。合并的过程,可以认为是分裂过程的逆过程。、
如果用主键自增

插入新记录的时候可以不指定ID的值,系统会获取当前ID最大值加1作为下一条记录的ID值。

也就是说,自增主键的插入数据模式,正符合了我们前面提到的递增插入的场景。每次插入一条新记录,都是追加操作,都不涉及到挪动其他记录,也不会触发叶子节点的分裂。

而有业务逻辑的字段做主键,则往往不容易保证有序插入,这样写数据成本相对较高。

4.回表?举例子。

回表是MySQL数据库中的一个重要概念,它涉及到数据库查询过程中的索引使用和数据行访问。在理解回表之前,我们需要先了解一些基本背景知识。

MySQL是一种关系型数据库管理系统,用于存储和管理大量结构化数据。在MySQL中,表格被分为多个行和列,每一行代表一个数据记录,每一列代表数据的一个属性。为了提高查询效率,MySQL引入了索引的概念。

索引是一种数据结构,它可以加快对表格的查询操作。通过索引,MySQL可以快速定位到满足条件的数据行,而不需要遍历整个表格。索引的实现方式有很多种,其中最常见的是B树(B-tree)索引。

而回表就是在使用索引进行查询时,当找到满足条件的索引记录后,MySQL还需要通过该索引记录再次访问原始的数据行,以获取完整的数据信息。
为了更好地理解回表的过程,我们以一个具体的例子来说明。

假设我们有一个名为"students"的表格,包含了以下列:id、name、age、score。我们希望查询某个学生的成绩。

  • 首先,我们需要创建这个表格:

    CREATE TABLE students (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    age INT,
    score FLOAT
    );

  • 然后,我们在id字段上创建一个索引:

    CREATE INDEX idx_id ON students (id);

  • 接下来,我们执行一条查询语句,查找学生ID为1的成绩:

    SELECT score FROM students WHERE id = 1;

MySQL在执行这个查询时,首先会使用索引定位到满足条件的索引记录。在本例中,我们通过索引idx_id可以直接找到id为1的索引记录。这个过程称为索引查找。

然而,索引只包含了id这个字段,不包含score字段的值。所以,在索引查找到id为1的索引记录后,MySQL需要回到原始的数据行,读取其中的score字段的值。这个过程就是回表操作。

回表的过程涉及从磁盘中读取原始数据行,并提取所需的字段值。这一步骤可能会引起额外的IO操作,因为磁盘读取通常比内存访问慢很多。因此,回表操作可能会对查询性能产生一定影响。

可以看出,回表是在查询过程中索引和数据行之间的切换。通过索引定位到数据行,再通过数据行获取所需的字段值。这个过程虽然增加了一定的开销,但也使得MySQL数据库能够高效地使用索引,减少了对整个表格的扫描,提升了查询效率。

回表操作的频率和开销与查询语句、索引和数据表的结构以及存储引擎等因素有关。如果频繁进行回表操作且性能成为瓶颈,可以通过调整索引策略、优化查询语句或者使用其他技术手段来改善性能。

总而言之,回表是MySQL数据库查询过程中的一个重要环节,涉及索引查找和数据行访问。通过理解回表的概念和原理,我们可以更好地优化数据库查询,提高系统的性能和响应速度。

相关推荐
晴殇i35 分钟前
揭秘JavaScript中那些“不冒泡”的DOM事件
前端·javascript·面试
绝无仅有1 小时前
Redis过期删除与内存淘汰策略详解
后端·面试·架构
绝无仅有1 小时前
Redis大Key问题排查与解决方案全解析
后端·面试·架构
AAA梅狸猫2 小时前
Looper.loop() 循环机制
面试
AAA梅狸猫2 小时前
Handler基本概念
面试
Wect3 小时前
浏览器缓存机制
前端·面试·浏览器
掘金安东尼3 小时前
Fun with TypeScript Generics:玩转 TS 泛型
前端·javascript·面试
掘金安东尼3 小时前
Next.js 企业级落地
前端·javascript·面试
掘金安东尼3 小时前
React 性能优化完全指南 2026
前端·javascript·面试
掘金安东尼14 小时前
让 JavaScript 更容易「善后」的新能力
前端·javascript·面试