SQL - MySQL回表

这篇具有很好参考价值的文章主要介绍了SQL - MySQL回表。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、回表概念;现象

回表,顾名思义就是回到表中,也就是先通过普通索引(我们自己建的索引不管是单列索引还是联合索引,都称为普通索引)扫描出数据所在的行,再通过行主键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默认的存储引擎 

回表,数据库DataBase,回表,聚簇索引,非聚簇索引,InnoDB

可以看出,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 的理解

回表,数据库DataBase,回表,聚簇索引,非聚簇索引,InnoDB

前者是 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文章来源地址https://www.toymoban.com/news/detail-780670.html

到了这里,关于SQL - MySQL回表的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • [MySQL]数据库原理1,三大范式,E-R图,DataBase,数据库管理系统(DBMS),Relationship,实体、属性、联系 映射基数,关系型数据库,联系的度数等——喵喵期末不挂科

    希望你开心,希望你健康,希望你幸福,希望你点赞! 最后的最后,关注喵,关注喵,关注喵,佬佬会看到更多有趣的博客哦!!! 喵喵喵,你对我真的很重要! 目录 前言 认识数据库 常见的数据库管理系统应用案例。       1.数据(Data)       2.数据库(DataBase ,简

    2024年02月04日
    浏览(47)
  • Navicat远程连接,Docker中的mysql,新建数据库时报错:1044 -Access denied for user ‘root‘@‘%‘ to database

     该错误表示root用户没有访问指定数据库的权限  解决办法就是重新赋权 1.访问 Docker 容器内的 MySQL 命令行界面 2.输入 root 用户的密码 注 : 密码是不会显示的,输入完后Enter即可 3.切换数据库 4.更新表host中的列,将根用户的mysql.user值设置为。\\\'%\\\' 注 :         默认情况

    2024年02月16日
    浏览(54)
  • [MySQL]数据库原理2,Server,DataBase,Connection,latin1、UTF-8,gb2312,Encoding,Default Collation——喵喵期末不挂科

    希望你开心,希望你健康,希望你幸福,希望你点赞! 最后的最后,关注喵,关注喵,关注喵,佬佬会看到更多有趣的博客哦!!! 喵喵喵,你对我真的很重要! 目录 前言 认识字符集和校对原则 MySQL 5.5支持的字符集和校对原则 常用字符集和校对原则 确定字符集和校对原

    2024年02月04日
    浏览(45)
  • 数据库应用:MySQL数据库SQL高级语句与操作

    目录 一、理论 1.克隆表与清空表 2.SQL高级语句 3.SQL函数 4.SQL高级操作 5.MySQL中6种常见的约束 二、实验  1.克隆表与清空表 2.SQL高级语句 3.SQL函数 4.SQL高级操作 5.主键表和外键表  三、总结 克隆表:将数据表的数据记录生成到新的表中。 (1)克隆表 ① 先创建再导入 ② 创建

    2024年02月13日
    浏览(81)
  • 【MySQL 数据库】7、SQL 优化

    ① 批量插入数据 ② 手动控制事务 ③ 主键顺序插入,性能要高于乱序插入 主键乱序插入 : 8 1 9 21 88 2 4 15 89 5 7 3 主键顺序插入 : 1 2 3 4 5 7 8 9 15 21 88 89 【☆】 】 ① 如果需要一次性插入大批量数据(百万级别),使用 insert 语句插入性能 很低 ② 可使用 MySQL 数据库提供的 loa

    2024年02月08日
    浏览(60)
  • 【MySQL数据库】MySQL 高级SQL 语句一

    ) % :百分号表示零个、一个或多个字符 _ :下划线表示单个字符 ‘A_Z’:所有以 ‘A’ 起头,另一个任何值的字符,且以 ‘Z’ 为结尾的字符串。例如,‘ABZ’ 和 ‘A2Z’ 都符合这一个模式,而 ‘AKKZ’ 并不符合 (因为在 A 和 Z 之间有两个字符,而不是一个字符)。 ‘ABC%’

    2024年02月09日
    浏览(241)
  • MySQL数据库基础(九):SQL约束

    文章目录 SQL约束 一、主键约束 二、非空约束 三、唯一约束 四、默认值约束 五、外键约束(了解) 六、总结 PRIMARY KEY 约束唯一标识数据库表中的每条记录。 主键必须包含唯一的值。 主键列不能包含 NULL 值。 每个表都应该有一个主键,并且每个表只能有一个主键。 遵循原

    2024年02月19日
    浏览(60)
  • MySQL之SQL与数据库简介

    SQL首先是一门高级语言,同其他的C/C++,Java等语言类似,不同的是他是一种结构化查询语言,用户访问和处理数据库的语言,那类似于C语言,SQL也有自己的标准,目前市面上的数据库系统都支持SQL-92标准 SQL这门语言是具有统一性的,但是不同的数据库支持的SQL有略微差别,

    2024年01月23日
    浏览(51)
  • 【数据库】MySQL 高级(进阶) SQL 语句

    location表格创建 store_info表格创建 显示表格中一个或数个字段的所有数据记录 不显示重复的数据记录 按照条件进行查询 在已知的字段数据取值范围内取值 另外还有not in命令,用法一致,表示显示不在指定范围内的字段的值。 在两个字段数据值之间取值,包含两边字段的数据

    2024年02月09日
    浏览(136)
  • 【MySQL】数据库SQL语句之DML

    目录 前言: 一.DML添加数据 1.1给指定字段添加数据 1.2给全部字段添加数据 1.3批量添加数据 二.DML修改数据 三.DML删除数据 四.结尾   时隔一周,啊苏今天来更新啦,简单说说这周在做些什么吧,上课、看书、放松等,哈哈哈,所以博客就这样被搁了。   今天感觉不错,给大

    2024年02月08日
    浏览(68)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包