【MySql】MySQL数据库--什么是MySQL的回表 ?
一、背景
先要从 InnoDB 的索引实现说起,InnoDB 有两大类索引:
-
聚集索引 (clustered index)
-
普通索引 (secondary index)
InnoDB 聚集索引和普通索引有什么差异?
InnoDB 普通索引 的叶子节点存储主键值。
注意:只有 InnoDB 普通索引才存储主键值,MyISAM 的二级索引都是直接指向数据块的。
InnoDB 聚集索引 的叶子节点存储行记录,因此,InnoDB 必须要有,且只有一个聚集索引:
如果表定义了主键,则主键就是聚集索引;
如果表没有定义主键,则第一个 not null 的 unique 列是聚集索引;
否则,InnoDB 会创建一个隐藏的 row-id 作为聚集索引;
注意:所以主键查询非常快,直接定位行记录。
二、什么是回表查询?
通俗的讲就是,如果索引的列在 select 所需获得的列中(因为在 mysql 中索引是根据索引列的值进行排序的,所以索引节点中存在该列中的部分值)或者根据一次索引查询就能获得记录就不需要回表,如果 select 所需获得列中有大量的非索引列,索引就需要到表中找到相应的列的信息,这就叫回表。
InnoDB聚集索引的叶子节点存储行记录,因此, InnoDB必须要有,且只有一个聚集索引:
(1)如果表定义了主键,则PK就是聚集索引;
(2)如果表没有定义主键,则第一个非空唯一索引(not NULL unique)列是聚集索引;
(3)否则,InnoDB会创建一个隐藏的row-id作为聚集索引;
三、可以举一个简单的例子
我有一张用于用户登录的user表:
字段名 | 类型 | 说明 |
---|---|---|
id | bigint(20) | 主键ID |
username | varchar(20) | 用户名 |
password | varchar(20) | 密码 |
假如现在有一个用户名为admin,密码为123的用户要登录,那我会先找出username为admin的那条用户数据
SELECT * FROM user WHERE username = 'admin'
再根据查出来的user信息去对比密码是否正确
这时你发现username字段是唯一的又经常作为where条件所以可以给username字段建一个索引,于是就给username建了一个普通的B+Tree索引。
这时候就出问题的,因为MySQL的InnoDB使用聚簇索引,具体的数据只和主键索引放在一起,其他的索引只存储了数据的地址(主键id)。
比如上面的例子中,我根据username索引找到的只是一个username为admin这条数据的id而不是这条数据信息,所以要找到整条数据信息要根据得到的id再去找。
看完上面的流程,你应该已经发现问题了,我要通过username找到id,再根据id找整条数据,这里有两个查找过程,这是影响效率的。就像上面的两个查找过程就是回表了。
四、解决办法
使用覆盖索引可以解决上面所说的回表的问题。
还是拿上面上面登录的例子来说,其实登录只需要判断用户名和密码,如果user表中有其他用户信息也是不需要的那我们能不能只查询一次就找到这个用户名对应的密码呢。
这个是可以的,上面所说的分两步查找,第一步根据username查找是肯定不能少的,那我们只要把password和索引username放到一起就可以了。我们可以建立一个(username、password)的组合索引,这里username一定要放在前面,然后我们把sql语句改一下
SELECT username, password FROM user WHERE username = 'admin'
或
SELECT password FROM user WHERE username = 'admin'
这样建立组合索引后根据username查找password,只要一步查找就可以查找到,因为password已经是username索引的一部分了,直接可以查出来,不再需要通过id找对应的整条数据。覆盖索引就是覆盖了多个列(字段)的索引。
五、更多如下图:
(1)先通过普通索引定位到主键值id=5;
(2)在通过聚集索引定位到行记录;
这就是所谓的回表查询,先定位主键值,再定位行记录,它的性能较扫一遍索引树更低。
六、总结
使用聚集索引(主键或第一个唯一索引)就不会回表,普通索引就会回表。
相关文章
- 【MySQL】解决mysql的 1594 错误
- 【MySql】mysql 数据库数据订正
- 第二百八十节,MySQL数据库-外键链表之一对多,多对多
- MySQL--执行mysql脚本及其脚本编写
- 数据库操作类mysql/mysqli/pdo
- 数据库内核月报 - 2015 / 05-MySQL · 引擎特性 · InnoDB redo log漫游
- 数据库内核月报 - 2015 / 09-MySQL · TokuDB · 文件目录谈
- PHP连接MySQL数据库的三种方式(mysql、mysqli、pdo)--续
- PHP连接MySQL数据库的三种方式(mysql、mysqli、pdo)
- mysql分布式数据库的逻辑库、物理库和分库分表和TDDL图文详解
- 详解MySQL information_schema数据库常用的表信息以及各表对应的字段信息;以及如何登录mysql和创建视图
- 104.第十九章 MySQL数据库 -- MySQL主从复制、 级联复制和双主复制(十四)
- 103.第十九章 MySQL数据库 -- MySQL的备份和恢复、MySQL主从复制(十三)
- 101.第十九章 MySQL数据库 -- MySQL的日志管理(十一)
- 100.第十九章 MySQL数据库 -- MySQL的并发控制(十)
- 93.第十九章 MySQL数据库 -- MySQL安装和基本使用(三)
- 91.第十九章 MySQL数据库 -- 数据库原理(一)
- mysql 主从不同步处理--数据库初始化
- Mysql之加密连接mysql_ssl_rsa_setup
- golang操作mysql数据库(Go-SQL-Driver/MySQL)
- MySQL数据库备份(INTO OUTFILE)
- python库Django链接mysql数据库做网站(二)--从网页向数据库中插入数据
- 1.1 下载安装mysql数据库服务器
- 猿创征文 | 国产数据库之在k8s环境下部署RadonDB MySQL集群
- zabbix使用percona插件监控mysql数据库(十九)