SQL - MySQL回表

2023-10-26

一、回表概念;现象

回表,顾名思义就是回到表中,也就是先通过普通索引(我们自己建的索引不管是单列索引还是联合索引,都称为普通索引)扫描出数据所在的行,再通过行主键ID 取出索引中未包含的数据。所以回表的产生也是需要一定条件的,如果一次索引查询就能获得所有的select 记录就不需要回表,如果select 所需获得列中有其他的非索引列,就会发生回表动作。即基于非主键索引的查询需要多扫描一棵索引树。

Mysql回表指的是在InnoDB存储引擎下,二级索引查询到的索引列,如果需要查找所有列的数据,则需要到主键索引里面去取出数据。这个过程就称为回表。因为行的数据都是存在主键B+tree的叶子节点里面,二级索引的B+树叶子节点都是存放的(索引列,主键)

简单来说,回表就是 MySQL 要先查询到主键索引,然后再用主键索引定位到数据

回表现象

举个例子:

表tbl有a,b,c三个字段,其中 a是主键,b上建了索引,然后编写sql语句SELECT * FROM tbl WHERE a=1这样不会产生回表,因为所有的数据在a的索引树中均能找到

如果是SELECT * FROM tbl WHERE b=1这样就会产生回表,因为where条件是b字段,那么会去b的索引树里查找数据,但b的索引里面只有a,b两个字段的值,没有c,那么这个查询为了取到c字段,就要取出主键a的值,然后去a的索引树去找c字段的数据。查了两个索引树,就出现了回表操作

二、存储引擎;索引结构

要弄明白回表,首先得了解MySQL的存储引擎,以及默认存储引擎 InnoDB 的两大索引,即聚簇索引 (clustered index)和 非聚簇索引/普通索引/二级索引/辅助索引(secondary index)

(一)存储引擎

MySQL中主要有2种存储引擎

1、MyISAM(不支持事物回滚)

MyIsam引擎是MySQL主流引擎之一,但它相比起InnoDB,没有提供对数据库事务的支持,不支持细粒度的锁(行锁)及外键,当表Insert与update时需要锁定整个表,因此效率会低一些,在高并发时可能会遇到瓶颈,但MyIsam引擎独立与操作系统,可以在windows及linux上使用。

可能的缺点:

不能在表损坏后恢复数据

适用场景:

1、MyIsam极度强调快速读取

2、MyIsam表中自动存储了表的行数,需要时直接获取即可

3、适用于不需要事物支持、外键功能、及需要对整个表加锁的情形

2、InnoDB(支持事物回滚)

InnoDB是一个事务型存储引擎,提供了对数据库ACID事务的支持,并实现了SQL标准的四种隔离级别,具有行级锁定(这一点说明锁的粒度小,在写数据时,不需要锁住整个表,因此适用于高并发情形)及外键支持(所有数据库引擎中独一份,仅有它支持外键)

该引擎的设计目标便是处理大容量数据的数据库系统,MySQL在运行时InnoDB会在内存中建立缓冲池,用于缓存数据及索引。

可能的缺点:

1、该引擎不支持FULLTEXT类型的索引

2、没有保存表的行数,在执行select count(*) from 表名 时,需要遍历扫描全表

适用场景:

1、经常需要更新的表,适合处理多重并发的更新请求

2、支持事务

3、外键约束

4、可以从灾难中恢复(通过bin-log日志等)

5、支持自动增加列属性auto_increment

show engines;

show engines; 查看mysql所支持的存储引擎,以及从中得到mysql默认的存储引擎 

可以看出,MySQL默认的数据库引擎是InnoDB

参数名称 解释说明
Engine 存储引擎名称
Support 是否支持该引擎以及该引擎是否为默认存储引擎,YES表示支持,NO表示不支持
DEFAULT DEFAULT表示为默认存储引擎
Comment 存储引擎的简单介绍
Transactions 表示该引擎是否支持事务
XA 说明该存储引擎是否支持分布事务
Savepoints 说明该存储引擎是否支持部分事务回滚

(二)索引结构

MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构。可以得到索引的本质:索引是数据结构

MySQL默认的数据库引擎是InnoDB,InnoDB 存储引擎的两大索引,即聚簇索引 (clustered index)和 非聚簇索引/普通索引/二级索引/辅助索引(secondary index)

1、聚簇索引 (clustered index)

InnoDB聚簇索引的叶子节点存储行记录,因此, InnoDB必须要有且只有一个聚簇索引。

  • 如果表定义了主键,则Primary Key 就是聚簇索引;
  • 如果表没有定义主键,则第一个非空唯一索引(Not NULL Unique)列是聚簇索引
  • 否则,InnoDB会创建一个隐藏的row-id作为聚簇索引

简单来说,聚簇索引是主键索引

2、非聚簇索引/普通索引/二级索引/辅助索引(secondary index)

主键索引之外的就是非聚簇索引,非聚簇索引又叫辅助索引或者二级索引

主键索引 和 非主键索引区别

相同点:都使用的是 B+Tree

不同点:叶子节点存储的数据不同

主键索引的叶子节点存储的是一行完整的数据

非主键索引的叶子节点存储的是主键值。叶子节点不包含记录的全部数据,非主键的叶子节点除了用来排序的 key 还包含一个书签(bookmark),其中存储了聚簇索引的 key

使用主键索引查询

# 主键索引的的叶子节点存储的是**一行完整的数据**,
# 所以只需搜索主键索引的 B+Tree 就可以轻松找到全部数据
select * from user where id = 1;

使用非主键索引查询

# 非主键索引的叶子节点存储的是**主键值**,
# 所以MySQL会先查询到 name 列的索引的 B+Tree,搜索得到对应的主键值
# 然后再去搜索该主键值查询主键索引的 B+Tree 才可以找到对应的数据
select * from user where name = 'Jack';

使用非主键索引要比主键索引多使用一次 B+Tree

二级索引查找的过程为先在二级索引找到主键索引的key,再在主键索引中查找(回表操作)

InnoDB表一定要建主键,并且最好使用int自增作为主键

这样做就是为了不用MySQL维护唯一列数据,节省资源。建立和维护索引过程中需要进行key的比较,int类型更好比较。自增使得树结构不容易产生树结构分裂,更节省算力

1、单值索引

即一个索引只包含单个列,一个表可以有多个单列索引

1

2

3

4

5

6

7

8

9

10

11

12

13

14

随表一起建索引:

CREATE TABLE customer (

id INT(10) UNSIGNED  AUTO_INCREMENT ,

customer_no VARCHAR(200),

customer_name VARCHAR(200),

PRIMARY KEY(id),

KEY (customer_name)

);

  

单独建单值索引:

CREATE  INDEX idx_customer_name ON customer(customer_name);

  

删除索引:

DROP INDEX idx_customer_name  on customer;

2、唯一索引

索引列的值必须唯一,但允许有空值

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

随表一起建索引:

CREATE TABLE customer (

id INT(10) UNSIGNED  AUTO_INCREMENT ,

customer_no VARCHAR(200),

customer_name VARCHAR(200),

  PRIMARY KEY(id),

  KEY (customer_name),

  UNIQUE (customer_no)

);

   

单独建唯一索引:

CREATE UNIQUE INDEX idx_customer_no ON customer(customer_no);

  

删除索引:

DROP INDEX idx_customer_no on customer ;

3、主键索引

设定为主键后数据库会自动建立索引,innodb为聚簇索引

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

随表一起建索引:

CREATE TABLE customer (

id INT(10) UNSIGNED  AUTO_INCREMENT ,

customer_no VARCHAR(200),

customer_name VARCHAR(200),

  PRIMARY KEY(id)

);

    

CREATE TABLE customer2 (

id INT(10) UNSIGNED   ,

customer_no VARCHAR(200),

customer_name VARCHAR(200),

  PRIMARY KEY(id)

);

  

 单独建主键索引:

ALTER TABLE customer

 add PRIMARY KEY customer(customer_no); 

  

删除建主键索引:

ALTER TABLE customer

 drop PRIMARY KEY

  

修改建主键索引:

必须先删除掉(drop)原索引,再新建(add)索引

4、复合索引

即一个索引包含多个列

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

随表一起建索引:

CREATE TABLE customer (

id INT(10) UNSIGNED  AUTO_INCREMENT ,

customer_no VARCHAR(200),

customer_name VARCHAR(200),

  PRIMARY KEY(id),

  KEY (customer_name),

  UNIQUE (customer_name),

  KEY (customer_no,customer_name)

);

  

单独建索引:

CREATE  INDEX idx_no_name ON customer(customer_no,customer_name);

  

删除索引:

DROP INDEX idx_no_name  on customer ;

(三)B-Tree 和 B+Tree

理解聚簇索引和非聚簇索引的关键在于 B+Tree 的理解

前者是 B-Tree,后者是 B+Tree,两者的区别在于:

  • B-Tree 中,所有节点都会带有指向具体记录的指针;B+Tree 中只有叶子结点会带有指向具体记录的指针。

  • B-Tree 中不同的叶子之间没有连在一起;B+Tree 中所有的叶子结点通过指针连接在一起。

  • B-Tree 中可能在非叶子结点就拿到了指向具体记录的指针,搜索效率不稳定;B+Tree 中,一定要到叶子结点中才可以获取到具体记录的指针,搜索效率稳定

基于上面两点分析,我们可以得出如下结论:

  • B+Tree 中,由于非叶子结点不带有指向具体记录的指针,所以非叶子结点中可以存储更多的索引项,这样就可以有效降低树的高度,进而提高搜索的效率。

  • B+Tree 中,叶子结点通过指针连接在一起,这样如果有范围扫描的需求,那么实现起来将非常容易,而对于 B-Tree,范围扫描则需要不停的在叶子结点和非叶子结点之间移动

三、索引创建场景

(一)需要创建索引

1、主键自动建立唯一索引

2、频繁作为查询条件的字段应该创建索引

3、查询中与其它表关联的字段,外键关系建立索引

4、单键/组合索引的选择问题, 组合索引性价比更高

5、查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度

6、查询中统计或者分组字段

(二)不要创建索引

1、表记录太少

2、经常增删改的表或者字段 原因:提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件

3、Where条件里用不到的字段不创建索引

4、过滤性不好的不适合建索引

四、覆盖索引避免回表

覆盖索引就是指索引中包含了查询中的所有字段,这种情况下就不需要再进行回表查询

一级索引:聚簇索引即主键索引
二级索引:非聚簇索引

一级B+Tree:叶子节点保存着键(id的值)和数据(全部字段的值)
二级B+Tree:叶子节点保存着键(索引字段的值)和数据(主键索引值)

查询 一级索引,根据一级B+Tree查询到数据,直接返回数据
查询 二级索引,根据二级B+Tree查询到对应的聚簇索引,再根据聚簇索引在一级B+Tree里查询到相应数据

查询 一级索引只需要扫描一次B+Tree。
查询 二级索引需要扫描两次B+Tree。根据二级B+Tree扫描的结果,再去一级B+Tree里进行扫描就叫回表操作

如果使用组合索引,就可以利用覆盖索引避免回表操作

例:表一共有五个字段:a(主键索引),b_c_d(组合索引),e(没有索引)

如果用户查询时只查 b,c,d;SELECT `b`, `c`, `d` FROM `table` WHERE `b` = 3 AND `c` = 7 AND `d` = 5;

因为查询的字段 b,c,d的值(B+Tree里的键) 已经在B+Tree里了,所以就可以直接返回,不用再拿聚簇索引去一级B+Tree里进行查询

如果查询字段为 a,b,c,d,因为a为主键索引,也保存在二级B+Tree的叶子节点里,所以也不用回表查询

【a是主键,给bcd建立联合索引】,如上几个sql,select出来的内容,和where条件字段,刚好和建立的索引一致

如果查询字段为 a,b,c,d,e,因为e没有在这个二级B+Tree里,所以需要进行回表操作,拿着主键索引再去一级B+Tree里进行查询

使用覆盖索引,我们需要select出来的列,都已经存在了索引树的叶子节点上。所以不需要回表操作,如果我们select出来的某列,不在该联合索引的叶子节点上(比如上表的e列),那就需要根据对应索引值,去聚簇索引树上回表查询对应的e列值了

参考链接

MySQL 回表 - 涛姐涛哥 - 博客园

什么是MySQL的回表?_一年春又来的博客-CSDN博客_回表

MySQL 存储引擎 - 知乎

https://www.jb51.net/article/239235.htm

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SQL - MySQL回表 的相关文章

随机推荐

  • Redis的内存淘汰机制和删除策略

    Redis内存淘汰机制 Redis内存淘汰指的是用户存储的一些键被可以被Redis主动地从实例中删除 内存的淘汰机制的初衷是为了更好地使用内存 配置 我们可以通过配置redis conf中的maxmemory这个值来开启内存淘汰功能 这个值
  • 【Python函数】——sort,sorted

    1 sorted和sort的常规使用 2 关于自定义比较函数 3 试验 from functools import cmp to key ll 2 3 10 1 2 3 5 6 7 2 5 10 2 4 10 根据一个维度进行排序 这里根据
  • sqli-labs Less-25、25a(sqli-labs闯关指南 25、25a)

    目录 Less 25 Less 25a Less 25 GET 基于错误 您所有的OR AND都属于我们 字符串单引号 源码 本关主要将 or and 进行了大小写的过滤 将其换成空 如何绕过 or 和 and 过滤 一般性提供以下几种思路
  • 国内第一篇讲解减少卡顿的代码级详细文章

    原文链接 原文链接 系统网站应用出现过卡顿 但却不知道如何优化 国内第一篇讲如何减少卡顿的代码级别详细文章 也是性能优化系列文章中的一篇 欢迎点赞 关注 也欢迎对其中的内容进行评论 经常听人说 不要阻塞主线程 或者 减少长耗时 该如何做呢
  • SQL Server 数据分页查询

    最近学习了一下SQL的分页查询 总结了以下几种方法 首先建立了一个表 随意插入的一些测试数据 表结构和数据如下图 现在假设我们要做的是每页5条数据 而现在我们要取第三页的数据 数据太少 就每页5条了 方法一 select top 5 fro
  • 火星数字

    火星人是以 13 进制计数的 地球人的 0 被火星人称为 tret 地球人数字 1 到 12 的火星文分别为 jan feb mar apr may jun jly aug sep oct nov dec 火星人将进位以后的 12 个高位数
  • attr 'explicit_paddings',tensorflow迁移到安卓报错不能载入模型

    attr explicit paddings tensorflow迁移到安卓报错不能载入模型 Android Stdio中报错 Caused by java io IOException Not a valid TensorFlow Gra
  • 第十章 网络工具--基于Linux3.10

    在测试io设备时 常常会用到iostat iotop工具 在查看内存时常常用到vmstat free slabtop工具 在查看调度器时 常常使用mpstat top以及ps工具 这里来说说网络相关的工具 有性能分析 网络管理 状态查看类工
  • App逆向案例 X嘟牛 - Frida监听 & WT-JS工具还原(一)

    App逆向案例 X嘟牛 Frida监听 WT JS工具还原 一 提示 文章仅供参考 禁止用于非法途径 文章目录 App逆向案例 X嘟牛 Frida监听 WT JS工具还原 一 前言 一 资源推荐 二 App抓包分析 三 反编译逆向分析 四
  • 2023华为产品测评官-开发者之声

    2023华为产品测评官 开发者之声 活动激发了众多开发者和技术爱好者的热情 他们纷纷递交了精心编写的产品测评报告 活动社群充满活力 参与者们热衷于交流讨论 互相帮助解决问题 一起探索云技术的无限可能 在此次活动中 华为云CodeArts获得
  • 守护线程

    守护线程是一类比较特殊的线程 一般用于处理后台的工作 比如JDK的垃圾回收线程 守护线程具备自动结束生命周期的特点 非守护线程不具备这样的特点 首先明确一个问题 JVM什么情况下会退出 The java virtual machine ex
  • 关于H.248的树图规则

    一 H248数图 数图可以是一个字符串 我们不妨称之为数图字符串 它遵循了Unix系统命令中的规则表达式的语法规定 也可以是许多数图字符串的并集 之间用 分隔 我们不妨称之为数图字符串列表 以下是一个数图的例子 2 8 xxxxxxx 13
  • RabbitMQ 与 Kafka 对比

    作为一个有丰富经验的微服务系统架构师 经常有人问我 应该选择RabbitMQ还是Kafka 基于某些原因 许多开发者会把这两种技术当做等价的来看待 的确 在一些案例场景下选择RabbitMQ还是Kafka没什么差别 但是这两种技术在底层实现
  • 【jackson】自定义字段注解完成序列化逻辑

    目录 背景 本文开发环境介绍 新建一个注解 新建一个JavaBean 新建一个JsonSerializer 新建一个AnnotationIntrospector 单元测试 总结 背景 Spring默认的JSON序列化工具使用的是jackso
  • 基于CNN-LSTM数据分类:Matlab实现

    基于CNN LSTM数据分类 Matlab实现 在当今的信息时代 数据处理和分类已经成为了不可或缺的技能和工具 其中卷积神经网络 Convolutional Neural Network CNN 和长短时记忆网络 Long Short Te
  • 多少存款才是裸辞的最好姿态?

    朋友小惠上个月裸辞了 前几天见她还意气风发 没想到昨晚就和我说 焦虑来得远比想象中快 她的计划是三个月内找到满意的新工作 满打满算攒了三个月的生活费才踏出裸辞这一步 结果面试了几个公司后 对于能否在三个月内找到满意工作感到极度地焦虑 小惠认
  • [SWPUCTF 2021 新生赛]finalrce

  • tplink 703n lede -17.01 编译过程

    tplink 703n lede 17 01 编译过程 tplink 703n lede 17 01 编译过程 tplink 703n 支持USB扩展 利用其功能可实现挂载硬盘 打印机共享等 网上虽然有些现成的固件 但基于openwrt 1
  • shiro(java安全框架)

    以下都是综合之前的人加上自己的一些小总结 Apache Shiro是一个强大且易用的Java安全框架 执行身份验证 授权 密码学和会话管理 使用Shiro的易于理解的API 您可以快速 轻松地获得任何应用程序 从最小的移动应用程序到最大的网
  • SQL - MySQL回表

    一 回表概念 现象 回表 顾名思义就是回到表中 也就是先通过普通索引 我们自己建的索引不管是单列索引还是联合索引 都称为普通索引 扫描出数据所在的行 再通过行主键ID 取出索引中未包含的数据 所以回表的产生也是需要一定条件的 如果一次索引查