[MySQL数据库] 索引详解

🌸个人主页:https://blog.csdn.net/2301_80050796?spm=1000.2115.3001.5343

🏵️热门专栏:

🧊 Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm=1001.2014.3001.5482

🍕 Collection与数据结构 (93平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm=1001.2014.3001.5482

🧀线程与网络(96平均质量分) https://blog.csdn.net/2301_80050796/category_12643370.html?spm=1001.2014.3001.5482

🍭MySql数据库(93平均质量分)https://blog.csdn.net/2301_80050796/category_12629890.html?spm=1001.2014.3001.5482

🍬算法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12676091.html?spm=1001.2014.3001.5482

🍃 Spring(97平均质量分)https://blog.csdn.net/2301_80050796/category_12724152.html?spm=1001.2014.3001.5482

🎃Redis(97平均质量分)https://blog.csdn.net/2301_80050796/category_12777129.html?spm=1001.2014.3001.5482

🐰RabbitMQ(97平均质量分) https://blog.csdn.net/2301_80050796/category_12792900.html?spm=1001.2014.3001.5482

感谢点赞与关注~~~

目录

  • [1. 索引概述](#1. 索引概述)
    • [1.1 概念](#1.1 概念)
    • [1.2 作用](#1.2 作用)
    • [1.3 使用场景](#1.3 使用场景)
    • [1.4 使用](#1.4 使用)
  • [2. 索引结构](#2. 索引结构)
    • [2.1 概述](#2.1 概述)
    • [2.2 不同的数据结构作为索引的情况](#2.2 不同的数据结构作为索引的情况)
  • [3. 索引的类型](#3. 索引的类型)
    • [3.1 索引的类型](#3.1 索引的类型)
    • [3.2 聚集索引&二级索引](#3.2 聚集索引&二级索引)
    • [3.3 前缀索引](#3.3 前缀索引)
  • [4. 索引语法](#4. 索引语法)
  • [5. sql性能分析](#5. sql性能分析)
    • [5.1 sql执行频率](#5.1 sql执行频率)
    • [5.2 慢日志查询](#5.2 慢日志查询)
    • [5.3 profile详情](#5.3 profile详情)
    • [5.4 explain](#5.4 explain)
  • [6. 索引失效](#6. 索引失效)
    • [6.1 最左前缀法则](#6.1 最左前缀法则)
    • [6.2 范围查询](#6.2 范围查询)
    • [6.3 索引列运算](#6.3 索引列运算)
    • [6.4 字符串不加引号](#6.4 字符串不加引号)
    • [6.5 模糊查询](#6.5 模糊查询)
    • [6.6 or连接条件](#6.6 or连接条件)
    • [6.7 数据分布影响](#6.7 数据分布影响)
  • [7. sql提示](#7. sql提示)
  • [9. 覆盖索引](#9. 覆盖索引)

1. 索引概述

1.1 概念

索引是帮助MySQL高效获取数据的数据结构,在数据之外,数据库还维护着满足特定算法的数据结构,这些数据结构以某种方式指向数据,这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引.

1.2 作用

  • 数据库中的表、数据、索引之间的关系,类似于书架上的图书、书籍内容和书籍目录的关系。
  • 索引所起的作用类似书籍目录,可用于快速定位、检索数据。
  • 索引对于提高数据库的性能有很大的帮助。

注意:引入索引可以提高数据库的查询速度,但是也会有一定的缺点:

  1. 目录本身也要占据一定的储存空间(一般是占据硬盘)
  2. 索引会拖慢增删改的速度,因为后续在对数据库更新的时候,也要同步更新索引.

我们举个例子来说明:

有请助教:凯亚,丽莎

最近凯亚在跟着丽莎学药物炼制,凯亚要想在丽莎这里通过考核,必须写出出色的药物炼制论文,一篇优秀的长篇学术论文是不可能没有目录的.凯亚费尽九牛二虎之力,终于把内容和目录全部写完了,但是有一天,凯亚发现,根据丽莎的要求,他少写了一种药物的相关内容.凯亚此时崩溃了,让他崩溃的不是正文内容,而是目录,前面目录的序号和页码标的好好的,结果要在中间插入内容,序号和页码全乱套了 .

1.3 使用场景

  • 针对于数据量较大,且查询比较频繁的表建立索引。
  • 针对于常作为查询条件(where)、排序(order by)、分组(group by)操作的字段建立索引。
  • 尽量选择区分度高的列作为索引,尽量建立唯一索引,区分度越高,使用索引的效率越高。
  • 如果是字符串类型的字段,字段的长度较长,可以针对于字段的特点,建立前缀索引。
  • 尽量使用联合索引,减少单列索引,查询时,联合索引很多时候可以覆盖索引,节省存储空间,避免回表,提高查询效率。
  • 要控制索引的数量,索引并不是多多益善,索引越多,维护索引结构的代价也就越大,会影响增删改的效率。
  • 如果索引列不能存储NULL值,请在创建表时使用NOT NULL约束它。当优化器知道每列是否包含NULL值时,它可以更好地确定哪个索引最有效地用于查询。

1.4 使用

创建主键约束,唯一约束,外键约束 时,会自动创建对应的索引.

原因如下:针对主键会有大量的查询行为 ,所以会自动创建.在往一个带有外键约束的表中添加元素的时候,外键约束会使得子表触发查询,要在父表中查询是否存在对应元素,查询操作也比较频繁.

  • 查看索引:
    show index from 表名
    show index from student;

    我们看到,由于student的id一列为主键,id一列就默认有索引存在.
  • 创建索引:
    对于非主键、非唯一约束、非外键的字段,可以创建普通索引
    create index 索引名 on 表名(列名)
    create index name_index on student(name);

    我们看到,name一列的索引被创建了.
  • 删除索引:
    drop index 索引名 on 表名
    drop index name_index on student;

    我们看到,name一列的索引被删除了.

2. 索引结构

2.1 概述

MySQL的索引是在存储引擎层实现的,不同的存储引擎有着不同的索引结构,主要包含一下几种:

索引结构 描述
B+树索引 最常见的索引类型,大部分引擎都支持B+树
Hash索引 底层数据结构是用Hash表实现的,只有精确匹配索引列的查询才有效,不支持范围查询
空间索引 空间索引是MyISAM引擎的一个特殊索引类型主要用于地理空间数据类型,使用较少
全文索引 是一种通过建立倒排索引,快速匹配文档的方式

不同的存储引擎对于索引结构的支持情况有所不同.

我们平常所说的索引,如果没有特别说明,都是指b+树索引.

2.2 不同的数据结构作为索引的情况

  • 二叉搜索树

    我们在之前讲述数据结构的时候也提到过,二叉搜索树在树是一颗单分支的情况之下,二叉搜索树查询的时间复杂度会由原来的O(log2N)变为O(N),就和顺序查询没有什么区别.所以他不适用于索引.

  • 红黑树

    为了使得二叉树平衡,我们便想到了红黑树.

    红黑树中,除非树里的元素是有序的,才可以进行范围查询,但是在红黑树中,找到中序遍历的下一个后继元素这样的操作也未必高效,很有可能需要往父节点上一系列回溯,才可以找到后继 .这种缺点可以通过"线索化"的方式来解决,但是也需要付出更多的存储空间.

    其次,红黑树也是一棵二叉搜索树,当元素非常多的时候,就会使得树的高度变高,树的高度越高,进行查询的效率就越低 .高度每增加一层,比较的次数就增加1,而数据库的数据和索引都是保存在硬盘上的,上述每次比较都需要一次硬盘IO操作,效率非常低下.

  • b+树

    由于前面的数据结构都不合适,我们就引入了B+树.B+树是B树的升级版本.B树和B+树同样都是一棵N叉搜索树.详情见数据结构章节的文章.

    B+树中,非叶子结点保存的是子树指针 ,指向关键字值属于[k[i],k[i+1])的子树,而最终的数据都保存在了叶子结点上,叶子结点的这一层,就包含的是整个数据集合的全集 .叶子结点都会多出一个链指针,把叶子结点之间都已链表的形式串联了起来.此时就可以通过上述的链式结构非常方便的遍历整个表中的所有数据,同时也非常方便进行范围查询 .

    比如我们在下面的B+树中进行这样的查询:select * from student where id >= 6 and id =< 9.

  • 首先拿到数据范围中的最小值6.

  • 接着从根节点开始遍历,第一个元素5大于6,接着下一个元素10大于6,遍历到10的左树.

  • 接着比较下一层的第一个元素,5大于6,接着比较下一个元素,7大于6,遍历到7的左树,到达叶子结点,找到6这个数据

  • 沿着链表向下遍历,直到数据等于9.

  • 上述例子是对表中主键索引(聚集索引)的查询过程,我们下面还会讲到二级索引的查询过程.

B+树作为索引相对于B树作为索引的优势(面试题)

  1. 非常方便的进行范围查询,由于叶子结点是一种链式结构,从而支持B+树的范围查询,而B树只能查询一个数据.
  2. 当前任何一次查询操作,最终都是要落到叶子结点上的.查询任何数据的时候,经过的树的高度都是一样的,经历的硬盘IO次数都是一样的.这个时候查询操作消耗的时间是稳定的.
  3. 由于叶子结点,是数据的全集(包括id,和其他列的数据),对应的非叶子结点中,都是重复出现的数据.就可以把表中的每一行的数据,最终都关联到叶子结点这一层,非叶子结点只保存一个单纯的key(id)即可.
  • Hash索引
    MySQL中除了支持b+树索引,还支持另一种索引类型--Hash索引
  1. 结构
    哈希索引就是采用一定的Hash算法,将键值换成新的Hash值,映射到对应的Hash槽位上,然后存储在Hash表中.采用的是哈希槽这样的思想,我们在之前的redis集群分片算法中也曾经提到过哈希槽分片算法.

    如果两个或者是多个键值,同时映射到了一个哈希槽位上,他们就产生了Hash冲突,也称为Hash碰撞,可以通过给哈希槽下面挂链表来解决.

    在MySQL中,支持Hash索引的是Memery存储引擎,而Innodb中具有自适应的Hash功能,Hash索引是Innodb存储引擎根据b+树索引在指定条件下自动构建的.

面试题: Hash索引和B+索引有什么区别?

  1. Hash索引使用的数据结构是Hash表,B+索引使用的是B+树(多路平衡搜索树)

  2. Hash索引只支持精确匹配查询,只能查询一个数据,不支持范围查询,b+树支持范围查询.

  3. Hash索引数据无序,b+树数据有序.所以Hash无法利用索引完成对数据的排序操作,而b+树可以.

  4. Hash索引需要解决Hash冲突,b+树没有数据冲突.

  5. MySQL的Memory存储引擎默认使用Hash索引,而InnoDB默认使用B+树索引
    面试题: 为什么使用b+树作为索引?

  6. 相对于二叉搜索树和红黑树,b+树在数据量比较大的时候,b+树每一层的数据量都是爆炸级别的增长,所以他的层级就会比较低,而红黑树或者是二叉搜索树在数据量比较大的时候,层级就会比较高,搜索效率较为低下.

  7. 非常方便的进行范围查询,由于叶子结点是一种链式结构,从而支持B+树的范围查询,而其他的只能查询一个数据.

  8. 当前任何一次查询操作,最终都是要落到叶子结点上的.查询任何数据的时候,经过的树的高度都是一样的,经历的硬盘IO次数都是一样的.这个时候查询操作消耗的时间是稳定的.
    理解第一条: 那么为什么说b+树的高度相对较低呢,假设一行数据的大小为1k,一页中可以存储16行这样的数据,Innodb的指针占用6个字节的空间,主键即使为bigint,占用字节数为8,高度为2的时候,n * 8 + (n + 1) * 6 = 16*1024 , 算出n约为 1170 , 1171* 16 = 18736, 也就是说,如果树的高度为2,则可以存储 18000 多条记录.高度为3的时候,n * 8 + (n + 1) * 6 = 16*1024 , 算出n约为 1170 ,1171* 16 = 18736 ,也就是说,如果树的高度为2,则可以存储 18000 多条记录.

3. 索引的类型

3.1 索引的类型

在MySQL数据库中,将索引的具体类型主要分为一下几类:

分类 含义 特点 关键字
主键索引 对于一个表中创建的索引 默认自动创建,只能有一个 Primary
唯一索引 避免同一个表中某数据列中的值重复 可以有多个 unique
常规索引 快速定位特定数据 可以有多个
全文索引 全文索引查找的是文本中的关键词,而不是比较索引中的值 可以有多个 fulltext

3.2 聚集索引&二级索引

在Innodb存储引擎中,根据索引的存储形式,又可以分为一下两种:

分类 含义 特点
聚集索引 将数据存储与索引放到一块,索引结构的叶子结点保存了行数据 必须有,而且只能有一个
二级索引 将数据与索引分开存储,索引结构的叶子节点关联的是对应的主键 可以存在多个

聚集索引选取的规则;

  • 如果主键存在,逐渐就是聚集索引
  • 如果不存在主键,将使用第一个唯一索引作为聚集索引
  • 如果表没有主键,或者没有合适的唯一索引,则Innodb会自动生成一个rowid作为隐藏的聚集缩影.

聚集索引和二级索引的具体结构如下:

  • 聚集索引的叶子结点下面挂的是这一行的数据.
  • 二级索引的叶子结点下面挂的是该字段的值对应的主键值.

接下来,我们来分析一下,当我们执行如下sql的时候,即命中二级索引的时候,具体查找的过程是怎么样的.

具体过程如下:

  1. 由于是根据name字段进行查询,所以先根据name='arm'name字段的二级索引中进行查询匹配,但是在二级索引中只能查询到arm对应的主键值10.
  2. 由于查询返回的数据是*,所以此时还需要根据主键值10,到聚集索引中查找10对应的记录,最终找到10对应的row.这个过程我们称为回表查询.
  3. 最终拿到这一行的数据,直接返回即可.

显然,相比我们在前面提到的直接命中聚集索引的情况,这种命中二级索引的情况需要涉及到回表查询,所以效率没有直接命中聚集索引的效率高.而直接命中聚集索引直接就可以在叶子结点返回当前行的数据.

3.3 前缀索引

当字段类型为字符串(varchar,text,longtext等)时,这会让索引变得很大,查询时,浪费大量的磁盘IO, 影响查询效率。此时可以只将字符串的一部分前缀,建立索引,这样可以大大节约索引空间,从而提高索引效率.

  • 语法:
sql 复制代码
create index idx_xxxx on table_name(column(n)) 

就只比建立索引的语法多出了column(n),其中n表示的是要对前几个字符建立索引.

  • 前缀长度
    可以根据索引的选择性来决定,而选择性是指不重复的索引值和数据表的记录总数的比值.索引选择性越高则查询效率越高.
sql 复制代码
select count(distinct email) / count(*) from tb_user ;
select count(distinct substring(email,1,5)) / count(*) from tb_user ;

substring(email,1,5)进行去重之后与数据总数做比值.

  • 前缀索引的查询流程

4. 索引语法

创建主键约束,唯一约束,外键约束 时,会自动创建对应的索引.

原因如下:针对主键会有大量的查询行为 ,所以会自动创建.在往一个带有外键约束的表中添加元素的时候,外键约束会使得子表触发查询,要在父表中查询是否存在对应元素,查询操作也比较频繁.

  • 查看索引:
    show index from 表名
    show index from student;

    我们看到,由于student的id一列为主键,id一列就默认有索引存在.
  • 创建索引:
    对于非主键、非唯一约束、非外键的字段,可以创建普通索引
    create index 索引名 on 表名(列名)
    create index name_index on student(name);

    我们看到,name一列的索引被创建了.
  • 删除索引:
    drop index 索引名 on 表名
    drop index name_index on student;

    我们看到,name一列的索引被删除了.

5. sql性能分析

5.1 sql执行频率

MySQL客户端连接成功之后,通过show [session|global] status命令可以提供服务器状态的信息,通过如下的指令,可以查询当前数据库的insert,Update,delete,select的反问频次:

sql 复制代码
-- session 是查看当前会话 ;
-- global 是查询全局数据 ;
SHOW GLOBAL STATUS LIKE 'Com_______';

通过对上述的指令,我们可以查看到当前数据库是以查询为主,还是以增删改为主,从而为数据库优化提供参考依据.如果是以增删改为主,我们可以考虑不对其进行索引优化,如果是以查询为主,那么就要考虑对数据库的索引进行优化了.

加入说是以查询为主,那么我们又该如何定位哪些查询语句进行优化呢?我们可以借助于慢查询日志.

5.2 慢日志查询

慢查询日志记录了所有执行时间超过指定参数的所有说起来语句日志(默认为10秒).

我们可以查看系统中的慢查询日志有没有开启,我们可以查看系统变量:slow_query_log:

sql 复制代码
show variables like 'slow_query_log';

如果要开启慢日志查询,我们需要在MySQL的配置文件中添加一下信息:

复制代码
# 开启MySQL慢日志查询开关
slow_query_log=1
# 设置慢日志的时间为2秒,SQL语句执行时间超过2秒,就会视为慢查询,记录慢查询日志
long_query_time=2

配置完毕之后,通过以下的指令重新启动MySQL服务器,再次查询慢日志是否启动.

当我们开启了慢查询日志之后,我们在执行了一个慢查询之后,我们在检查慢日志之后,我们会发现,在慢日志中,会记录我们执行的慢查询的相关信息.慢日志默认在/var/lib/mysql/localhost-slow.log中.

通过慢日志,我们就可以定位出执行效率比较低的sql,从而有针对性的进行优化.

5.3 profile详情

show profile能够在做sql优化的时候帮助我们了解时间都耗费到哪里去了,通过have_profiling参数,就能够看到当前MySQL是否支持profile操作.

sql 复制代码
select @@have_profiling;

当前可以看到,MySQL支持profile操作,如果是关闭的,可以通过set语句在session/global级别开启profiling

sql 复制代码
set profiling = 1

开启之后,然后就可以通过如下的指令查看指令的执行耗时:

sql 复制代码
-- 查看每一条SQL的耗时基本情况
show profiles;
-- 查看指定query_id的SQL语句各个阶段的耗时情况
show profile for query query_id;
-- 查看指定query_id的SQL语句CPU的使用情况
show profile cpu for query query_id;

查看每一条sql的耗时情况:

查看指定sql各个阶段的耗时情况:

5.4 explain

explain或者desc命令获取MySQL如何执行select语句的信息,包括在select语句执行过程中表如何连接和连接的顺序.

语法:

sql 复制代码
-- 直接在select语句之前加上关键字 explain / desc
EXPLAIN SELECT 字段列表 FROM 表名 WHERE 条件 ;

Explain执行计划中各各字段的含义:

6. 索引失效

首先就是联合索引之下的两种情况

6.1 最左前缀法则

如果索引了多列(联合索引) ,要遵循最左前缀法则,最左前缀法则指的是查询从索引的最左列开始,并且不跳过索引中的列,如果跳过某一列,索引将会部分失效(后面的字段索引失效).

tb_user为例,我们先来看一下之前的tb_user表所创建的索引.

tb_user表中,有一个联合索引,这个联合索引中涉及到三个字段,顺序分别为: profession,age,status.

对于最左前缀法则指的是,查询的时候,最左边的索引列,也就是profession必须存在,否则索引全部失效.比如下面的查询,索引就会全部失效:

sql 复制代码
explain select * from tb_user where age = 31 and status = '0';

where中只有age和status两个字段.

由于最左边的索引列不存在,索引就会全部失效,我们看到key那一列为null.

再比如下面的一种情况,索引会部分失效:

sql 复制代码
explain select * from tb_user where profession = '软件工程' and status = '0';

注意: 只要最左边的列存在,索引即可生效,和编写sql的顺序无关.

6.2 范围查询

联合索引中,出现范围查询(<,>),范围查询右侧的列索引失效.

sql 复制代码
explain select * from tb_user where profession = '软件工程' and age > 30 and status = '0';

当范围查询使用了<或者>的时候,走了联合索引,但是索引的长度为49,说明范围查询右边的status字段是没有走索引的.

但是当范围查询使用<=或者>=之后,走联合索引,索引的长度为54,就说明所有字段都是走索引的.

所以,在业务允许的情况之下,尽可能的使用类似于>=或者是<=这类的范围查询,而避免使用> 或者 <.

其次就是单列索引

6.3 索引列运算

不要在索引上进行运算操作,否则索引将失效:

在tb_user中,处理前面介绍的联合索引之外,还有一个索引,是phone字段的单列索引.

比如根据phone字段进行函数运算操作之后,索引失效.

sql 复制代码
explain select * from tb_user where substring(phone,10,2) = '15';

6.4 字符串不加引号

字符串类型字段使用的时候,不加引号,索引将会失效.

接下来我们通过两组示例,来看看对于字符串类型的字段,加单引号与不加单引号的区别:

sql 复制代码
explain select * from tb_user where phone = '17799990015';
explain select * from tb_user where phone = 17799990015;

经过上面两组示例,我们会明显发现,如果字符串不加引号,对于查询结果,没有什么影响,但是数据库存在隐式类型转换,索引将会失效.

6.5 模糊查询

如果仅仅是尾部模糊匹配,索引不会失效,如果是头部模糊匹配,索引失效.

接下来,我们来看一下这三条sql语句的执行结果,查看一下执行计划:

sql 复制代码
explain select * from tb_user where profession like '软件%';
explain select * from tb_user where profession like '%工程';
explain select * from tb_user where profession like '%工%';

经过上述的测试,我们发现,在like模糊查询中,关键字后面加%,索引可以生效,而如果在关键字前面加了%,索引将会失效.

6.6 or连接条件

用or分割开的条件,如果or两边的条件中,有一个字段没有索引,那么另一个字段设计的索引都不会被用到.

sql 复制代码
explain select * from tb_user where id = 10 or age = 23;
explain select * from tb_user where phone = '17799990017' or age = 23;

由于age没有索引,所以即使id,phone有索引,索引也会失效,所以需要针对对于age也要建立索引.

然后我们可以对age字段建立索引:

sql 复制代码
create index idx_user_age on tb_user(age);

建立索引之后,我们再次执行sql语句,看看执行前后的计划变化:

最终我们发现,当or连接的条件,左右两侧的字段都有索引的时候,索引才会生效.

6.7 数据分布影响

如果MySQL评估使用索引比全表遍历更慢,那么就不适用索引:

sql 复制代码
select * from tb_user where phone >= '17799990005';
select * from tb_user where phone >= '17799990015';


经过测试,我们发现相同的sql语句,只是传入的字段值不同,最终对索引的使用情况完全不一样,这是因为MySQL在查询的时候,会评估使用索引的效率与走全表扫描的效率,如果走全表扫描更快,则放弃索引,走全表扫描.

7. sql提示

sql提示,是一种数据库优化的重要手段,简单来说,就是在sql语句中加入一些人为的提示来达到优化操作的目的:

  1. use index: 建议MySQL使用哪一个索引完成此次查询(仅仅是建议,MySQL内部还会再次进行评估).
sql 复制代码
explain select * from tb_user use index(idx_user_pro) where profession = '软件工程';
  1. ignore: 忽略指定的索引
sql 复制代码
explain select * from tb_user ignore index(idx_user_pro) where profession = '软件工程';
  1. force index: 强制使用索引.
sql 复制代码
explain select * from tb_user force index(idx_user_pro) where profession = '软件工程';

9. 覆盖索引

尽量使用覆盖索引,减少select *,那么什么是覆盖索引呢?覆盖索引是指,查询使用了索引,并且需要返回的列,在该索引中已经全部能够找到.

接下来我们来看一组sql的执行计划,看看执行计划的差别,然后再来具体做解析.

sql 复制代码
explain select id, profession from tb_user where profession = '软件工程' and age = 
31 and status = '0' ;
explain select id,profession,age, status from tb_user where profession = '软件工程' and age = 31 and status = '0' ;
explain select id,profession,age, status, name from tb_user where profession = '软件工程' and age = 31 and status = '0' ;
explain select * from tb_user where profession = '软件工程' and age = 31 and status = '0';

上述这几条sql的执行结果:

我们发现,后面的附加信息里面,前面两个sql语句为using where;using index,后面两个为using index condition.

因为在tb_user中有一个联合索引,idx_user_pro_age_sta,该索引关联了三个字段:profession、age、status,而这个也是一个二级索引,所以叶子节点下面挂的是这一行的主键id.所以当我们查询返回的数据在id、profession、age、status之中,则直接走二级索引就可以返回数据了,如果超出这个范围,就需要拿到主键的id,再去扫描聚集索引,再获取额外的数据了,这个过程就是回表,如果我们一直使用select *查询返回所有字段值,很容易造成回表查询.除非select *的查询条件命中主键,会直接从聚集索引中查询,直接返回叶子结点的数据全集.

下面是图解的详细过程:

  1. id是主键,是一个聚集索引,name字段建立了普通索引,是一个二级索引.
  2. 执行sql; select * from tb_user where id = 2;

    根据id查询,直接走聚集索引查询,一次索引扫描,直接返回数据,性能高.
  3. 执行select id,name from tb_user where name = 'Arm';

    虽然是根据name字段查询,查询二级索引,但是由于查询返回在字段为id,name,在name的二级索引中,这两个值都是可以直接获取到的,因为覆盖索引,所以不需要回表,性能高.
  4. 执行selet id,name,gender from tb_user where name = 'Arm'

    由于在name的耳机索引中,不包含gender,所以需要两次索引扫描,也就是需要回表查询,性能相对较差.

面试题: 有四个字段(id, username, password, status), 由于数据量大, 需要对SQL语句进行优化, 该如何进行才是最优方案.

针对username,password,status建立联合索引避免回表查询.

相关推荐
患得患失9492 分钟前
【后端】【Django DRF】从零实现RBAC 权限管理系统
数据库·django·sqlite
__淡墨青衫__18 分钟前
Django之旅:第五节--Mysql数据库操作(一)
数据库·mysql·django
橙序研工坊2 小时前
MySQL的基础语法1(增删改查、DDL、DML、DQL和DCL)
数据库·sql·mysql·database
晴天Y282 小时前
redis部署架构
数据库·redis·架构
gjc5923 小时前
MySQL源码学习系列(二)--面试高频问题:general log、slowlog记录顺序
数据库·学习·mysql·面试·职场和发展
晓oi3 小时前
MySQL———作业实验
数据库·mysql
hh_fine3 小时前
解决 “Cannot read SQL script from class path resource [sql/XX.sql]“ 错误
数据库·sql
余华余华3 小时前
VSCODE npm: 因为在此系统上禁止运行脚本。有关详细信息,请参阅 ...
java·服务器·数据库·笔记·oracle
不剪发的Tony老师3 小时前
IvorySQL:兼容Oracle数据库的开源PostgreSQL
数据库·postgresql·oracle
独行soc3 小时前
2025年渗透测试面试题总结-某快手-安全工程师(题目+回答)
网络·数据库·python·安全·面试·职场和发展·红蓝攻防