1. 索引结构

要搞明白这个问题,需要大家首先明白 MySQL 中索引存储的数据结构。这个其实很多小伙伴可能也都听说过,B+Tree 嘛!

B+Tree 是什么?那你得先明白什么是 B-Tree,来看如下一张图:

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

  1. B-Tree 中,所有节点都会带有指向具体记录的指针;B+Tree 中只有叶子结点会带有指向具体记录的指针。
  2. B-Tree 中不同的叶子之间没有连在一起;B+Tree 中所有的叶子结点通过指针连接在一起。
  3. B-Tree 中可能在非叶子结点就拿到了指向具体记录的指针,搜索效率不稳定;B+Tree 中,一定要到叶子结点中才可以获取到具体记录的指针,搜索效率稳定。

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

  1. B+Tree 中,由于非叶子结点不带有指向具体记录的指针,所以非叶子结点中可以存储更多的索引项,这样就可以有效降低树的高度,进而提高搜索的效率。
  2. B+Tree 中,叶子结点通过指针连接在一起,这样如果有范围扫描的需求,那么实现起来将非常容易,而对于 B-Tree,范围扫描则需要不停的在叶子结点和非叶子结点之间移动。

对于第一点,一个 B+Tree 可以存多少条数据呢?以主键索引的 B+Tree 为例(二级索引存储数据量的计算原理类似,但是叶子节点和非叶子节点上存储的数据格式略有差异),我们可以简单算一下。

计算机在存储数据的时候,最小存储单元是扇区,一个扇区的大小是 512 字节,而文件系统(例如 XFS/EXT4)最小单元是块,一个块的大小是 4KB。InnoDB 引擎存储数据的时候,是以页为单位的,每个数据页的大小默认是 16KB,即四个块。

基于这样的知识储备,我们可以大致算一下一个 B+Tree 能存多少数据。

假设数据库中一条记录是 1KB,那么一个页就可以存 16 条数据(叶子结点);对于非叶子结点存储的则是主键值+指针,在 InnoDB 中,一个指针的大小是 6 个字节,假设我们的主键是 bigint ,那么主键占 8 个字节,当然还有其他一些头信息也会占用字节我们这里就不考虑了,我们大概算一下,小伙伴们心里有数即可:

16*1024/(8+6)=1170

即一个非叶子结点可以指向 1170 个页,那么一个三层的 B+Tree 可以存储的数据量为:

1170*1170*16=21902400

可以存储 2100万 条数据。

在 InnoDB 存储引擎中,B+Tree 的高度一般为 2-4 层,这就可以满足千万级的数据的存储,查找数据的时候,一次页的查找代表一次 IO,那我们通过主键索引查询的时候,其实最多只需要 2-4 次 IO 操作就可以了。

大家先搞明白这个 B+Tree。

2. 两类索引

大家知道,MySQL 中的索引有很多中不同的分类方式,可以按照数据结构分,可以按照逻辑角度分,也可以按照物理存储分,其中,按照物理存储方式,可以分为聚簇索引和非聚簇索引。

我们日常所说的主键索引,其实就是聚簇索引(Clustered Index);主键索引之外,其他的都称之为非主键索引,非主键索引也被称为二级索引(Secondary Index),或者叫作辅助索引。

对于主键索引和非主键索引,使用的数据结构都是 B+Tree,唯一的区别在于叶子结点中存储的内容不同:

  • 主键索引的叶子结点存储的是一行完整的数据。
  • 非主键索引的叶子结点存储的则是主键值。

这就是两者最大的区别。

所以,当我们需要查询的时候:

  1. 如果是通过主键索引来查询数据,例如 select * from user where id=100,那么此时只需要搜索主键索引的 B+Tree 就可以找到数据。
  2. 如果是通过非主键索引来查询数据,例如 select * from user where username='javaboy',那么此时需要先搜索 username 这一列索引的 B+Tree,搜索完成后得到主键的值,然后再去搜索主键索引的 B+Tree,就可以获取到一行完整的数据。

对于第二种查询方式而言,一共搜索了两棵 B+Tree,第一次搜索 B+Tree 拿到主键值后再去搜索主键索引的 B+Tree,这个过程就是所谓的回表。

从上面的分析中我们也能看出,通过非主键索引查询要扫描两棵 B+Tree,而通过主键索引查询只需要扫描一棵 B+Tree,所以如果条件允许,还是建议在查询中优先选择通过主键索引进行搜索。

3. 一定会回表吗?

那么不用主键索引就一定需要回表吗?

不一定!

如果查询的列本身就存在于索引中,那么即使使用二级索引,一样也是不需要回表的。

举个例子,我有如下一张表:

uname 和 address 字段组成了一个复合索引,那么此时,虽然这是一个二级索引,但是索引树的叶子节点中除了保存主键值,也保存了 address 的值。

我们来看如下分析:

可以看到,此时使用到了 uname 索引,但是最后的 Extra 的值为 Using index,这就表示用到了索引覆盖扫描(覆盖索引),此时直接从索引中过滤不需要的记录并返回命中的结果,这一步是在 MySQL 服务器层完成的,并且不需要回表。

4. 扩展

基于第一、二小节的分析,我们再来捋一捋为什么在数据库中建议使用自增主键。

  1. 自增主键往往占用空间比较小,int 占 4 个字节,bigint 占 8 个字节。由于二级索引的叶子节点存储的就是主键,所以如果主键占用空间小,意味着二级索引的叶子节点将来占用的空间小(间接降低 B+Tree 的高度,提高搜索效率)。
  2. 自增主键插入的时候比较快,直接插入即可,不会涉及到叶子节点分裂等问题(不需要挪动其他记录);而其他非自增主键插入的时候,可能要插入到两个已有的数据中间,就有可能导致叶子节点分裂等问题,插入效率低(要挪动其他记录)。

生动的解释下什么是 MySQL 的“回表”?相关推荐

  1. 【MySQL】回表与覆盖索引

    目录 索引分类 聚簇索引 回表 覆盖索引(Cover Index) 索引分类 索引可以按照以下几个角度进行分类: 从数据结构的角度分类 B+tree 索引 Hash 索引 Full-texts索引 从 ...

  2. 关于mysql数据库回表的粗浅理解

    1关于mysql数据库回表 说一下现象 比如有有一张test表,设置id为主键,name为索引 当使用 select id,name,age from test where id=1 查询数据的时候, ...

  3. 什么是MySQL的回表?

    文章目录 引言 聚簇索引和非聚簇索引是什么? 主键索引和非主键索引有什么区别? B-Tree 和 B+Tree 的简单理解 如何避免回表? 引言 简单来说,回表就是 MySQL 要先查询到主键索引,然 ...

  4. mysql查询回表什么意思_什么是MYSQL回表查询

    select id,name where name='shenjian' select id,name,sex where name='shenjian' 多查询了一个属性,为何检索过程完全不同? 什 ...

  5. MySQL数据库——回表

    什么是回表 可以举一个简单的例子,我有一张用于用户登录的user表: 字段名 类型 说明 id bigint(20) 主键ID username varchar(20) 用户名 password va ...

  6. mysql回表什么意思_什么是Mysql的回表查询?聊一聊

    要说回表查询,先要从InnoDB的索引实现说起.InnoDB有两大类索引,一类是聚集索引(Clustered Index),一类是普通索引(Secondary Index). InnoDB的聚集索引 ...

  7. SQL - MySQL回表

    一.回表概念:现象 回表,顾名思义就是回到表中,也就是先通过普通索引(我们自己建的索引不管是单列索引还是联合索引,都称为普通索引)扫描出数据所在的行,再通过行主键ID 取出索引中未包含的数据.所以回表 ...

  8. MySQL 排查锁表常用SQL

    文章目录 MySQL 排查锁表常用Sql 锁信息 查询是否被锁的表 查询innodb事务获取的锁 查询会话 当前会话列表 基于IP过滤 基于数据库过滤 会话详情 查询会话执行过的sql 杀死会话 杀死 ...

  9. mysql回表查询uuid_MySQL数据库回表与索引

    [TOC] 回表的概念 先得出结论,根据下面的实验.如果我要获得['liu','25']这条记录.需要什么步骤. 1.先通过['liu']记录对应到普通索引index(name),获取到主键id:4. ...

最新文章

  1. 每天一个linux命令(12):more命令
  2. Docker简单的使用命令
  3. python输入end退出循环_4.学习python获取用户输入和while循环及if判断语句
  4. Codeforces 348C:Subset Sums
  5. android.app.instrumentation解析
  6. 请领导批阅文件怎么说_有请考过的说物业经理资格证怎么考?
  7. oracle linux 镜像下载|【最新】oracle linux 8.1官网镜像下载,让你下载oracle linux不被坑!
  8. 3年才能驾驭新技术,不如试试这个低代码魔方
  9. window xp 自动关机命令
  10. 【向生活低头】联想云教室同步win10_64位电脑导致的电脑卡死在lenovo界面
  11. novipnoad电影网站分析
  12. DP(Nietzsche)的hu测 T3(规律?主席树)
  13. JS控制台报错Uncaught TypeError Cannot read properties of null (reading ‘appendChild‘);的解决方法
  14. table 点击文字按钮预览图片
  15. Ubuntu 开机时间
  16. 苹果cms8整合dplayer播放器
  17. win7系统计算机无最小化,win7我的电脑图标没了win7我的电脑不见解决方法(图)
  18. 计算机网络体系结构划分
  19. GBase 8s基本数据类型
  20. POJO VO PO DTO 和JavaBean

热门文章

  1. Engineering:王军和张发明组发表人体肠道菌群的原位重建及昼夜节律的研究
  2. 17日南土所蒋瑀霁报告:红壤团聚体尺度养分转化的生物学过程(线虫-微生物互作机制)...
  3. 病毒进入体内的48小时
  4. 鱼和熊掌可以兼得! 天昊生物微生物16S扩增子绝对定量测序检测新模式创双赢!...
  5. 用polt3画曲面_用SolidWorks建模一个:防滑板曲面造型
  6. pandas使用pad函数向dataframe特定数据列的每个字符串添加补齐字符或者字符串、向所有字符串的左右两侧填充、直到宽度达到指定要求(both padding)
  7. K近邻(KNN)算法是基于实例的算法,如果训练样本数量庞大,预测的时候挨个计算距离效率会很低下,如何破解?
  8. 广义线性模型、Logistic、sigmoid、softmax、多分类、与大数据、优缺点
  9. R语言定量变量组间差异检验
  10. Linux grep 命令